1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(ggsn)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots


plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, ...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    median_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf")) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    median_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_shape_discrete(name="") +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          title = element_text(size=14),
          axis.text.x = element_text(size=10, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=12)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time


summarise_change <- function(model_data, model, population_denominator, grouping_var=NULL){

  #a. immediate change
  nd_immediate <- {{model_data}} %>%
    filter(year %in% c(1956:1957)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  immediate_change <- add_epred_draws({{model}},
                                      newdata=nd_immediate) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Immediate change") %>%
    ungroup()
  
  #b. post-ACF change
  nd_post <- {{model_data}} %>%
    filter(year %in% c(1956,1958)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  post_change <- add_epred_draws({{model}},
                                      newdata=nd_post) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Post-ACF change") %>%
    ungroup()
  
  #c. change in slope post vs. pre-ACF
  slope_change <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{grouping_var}}) %>%
    filter(year!=1957) %>%
    add_epred_draws({{model}}) %>%
    mutate(inc_100k = .epred/{{population_denominator}}*100000) %>%
    group_by(year, {{grouping_var}}, acf_period, ) %>%
    mean_qi(inc_100k) %>%
    ungroup() %>%
    mutate(n_years = length(year), .by=c(acf_period, {{grouping_var}})) %>%
    summarise(pct_change_epred_overall = (((last(inc_100k) - first(inc_100k))/first(inc_100k))),
              pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
              pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
      
              pct_change_epred_annual = (((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years),
              pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
              pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
              .by = c(acf_period, {{grouping_var}})) %>%
    distinct() %>%
    mutate(change = "Slope change")

  lst(immediate_change, post_change, slope_change)
    
}

Function for calculating difference from counterfactual

calcuate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf)
  
  #Calcuate incidence per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred)  %>%
      group_by(.draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
  
  #Calcuate incidence per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}

2. Data

Import datasets for analysis

2.1 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotlan with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))
Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey(base_family = "Segoe UI") +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold"))) +
  scalebar(glasgow_wards_1951, dist = 2, dist_unit = "km",
             transform = TRUE, model = "WGS84", location="bottomleft")

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

ward_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.5) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(ward~., ncol=6) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name="Division") +
  scale_colour_brewer(palette = "Set3", name = "Division") +
  labs(
    title = "Glasgow City: total population by Ward",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

ggsave(here("figures/s2.png"), height=10, width=12)

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="white", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("mediumseagreen", "purple"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s3.png"), width=10)
Saving 10 x 4.51 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to case cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB incidence

5.1 Overall TB incidence

Now calculate incidence per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.51 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

7. Overall pulmonary TB model

7.1 FIt the model and priors

First model will investigate the impact of mass miniature X-ray campaign on pulmonary TB case notification rate using an interrupted time series analysis.

Set up the data


mdata1 <- overall_inc %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(y_num = 1:nrow(.)) %>%
  rename(extrapulmonary_notifications = `non-pulmonary_notifications`)

Work on the priors a bit

Basic prior


basic_prior <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.25), class = b))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata1$pulmonary_notifications)
[1] 1858.429
#variance of counts per year
var(mdata1$pulmonary_notifications)
[1] 716579.8

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Slightly more informative prior (“weakly informative” really)


ggplot(data = tibble(x = seq(from = 500, to = 5000, by = 10)),
       aes(x = x, y = dgamma(x, shape = 0.1, rate = 0.00001))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  coord_cartesian(xlim = c(500, 5000)) +
  ggtitle(expression(brms~~gamma(0.1*", "*0.00001)~shape~prior))

NA
NA

Fit a model with only priors


winform_prior <- c(prior(normal(0, 1), class = Intercept),
                  prior(gamma(0.1, 0.00001), class = shape),
                  prior(normal(0, 0.25), class = b))


m_pulmonary_prior <- brm(
  pulmonary_notifications ~ y_num + acf_period + acf_period:y_num +  offset(log(total_population)),
                  data = mdata1,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior,
                  sample_prior = "only",
                  backend="cmdstanr",
                  save_pars = save_pars(all = TRUE),
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpvqbQUj/model-115da3e1ad624.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.

/
0/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]

-
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|
1 warning generated.

/

-
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

\

|

/

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 0.1 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.1 seconds.
Chain 4 finished in 0.1 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.1 seconds.
Total execution time: 0.6 seconds.
Warning: 86 of 4000 (2.0%) transitions ended with a divergence.
See https://mc-stan.org/misc/warnings for details.
summary(m_pulmonary_prior)
Warning: There were 86 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: pulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -0.05      2.48    -5.09     4.62 1.00     2538     2031
y_num                          0.00      0.25    -0.50     0.48 1.00     2589     2402
acf_periodb.acf                0.00      0.25    -0.49     0.48 1.00     2908     1869
acf_periodc.postMacf           0.01      0.25    -0.48     0.49 1.00     2668     2293
y_num:acf_periodb.acf         -0.00      0.25    -0.49     0.46 1.00     2714     2401
y_num:acf_periodc.postMacf     0.00      0.26    -0.51     0.54 1.00     2137     1486

Family Specific Parameters: 
      Estimate Est.Error l-95% CI  u-95% CI Rhat Bulk_ESS Tail_ESS
shape 11729.33  36453.14     0.00 104278.62 1.01      937      801

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
conditional_effects(m_pulmonary_prior)

Now fit the model with the weakly informative priors

m_pulmonary_overall <- brm(
  pulmonary_notifications ~ y_num + acf_period + acf_period:y_num +  offset(log(total_population)),
                  data = mdata1,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpvqbQUj/model-115da2adb5f52.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.

-
0/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here

\
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|
1 warning generated.

/

-
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

\

|

/

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 finished in 0.5 seconds.
Chain 2 finished in 0.4 seconds.
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 0.4 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 0.5 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.5 seconds.
Total execution time: 0.8 seconds.
summary(m_pulmonary_overall)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: pulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.10      0.03    -6.17    -6.04 1.00     2999     2234
y_num                         -0.02      0.01    -0.03    -0.01 1.00     2904     2266
acf_periodb.acf                0.02      0.25    -0.45     0.53 1.00     1764     2081
acf_periodc.postMacf           0.05      0.11    -0.19     0.26 1.00     1935     1892
y_num:acf_periodb.acf          0.08      0.03     0.01     0.14 1.00     1755     2160
y_num:acf_periodc.postMacf    -0.05      0.01    -0.08    -0.03 1.00     1821     1648

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape  4409.62  15136.27   322.80 26935.74 1.00     1318     1213

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_pulmonary_overall)

pp_check(m_pulmonary_overall, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

7.2 Summarise change in CNRs

Summarise the posterior


f1b <- plot_counterfactual(model_data = mdata1, model = m_pulmonary_overall, population_denominator = total_population, outcome = inc_pulm_100k, grouping_var=NULL)
  
f1b

Make this into a figure


f1a <- st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top",
        #legend.key.width = unit(2, "cm"),
        legend.title.align = 0.5) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`
(f1a / f1b) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f1.png"))
Saving 7.29 x 4.51 in image

Summary of change in notifications


summarise_change(model_data=mdata1, model=m_pulmonary_overall, population_denominator=total_population, grouping_var=NULL) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

(Alternative way - keep in for now)


overall_immediate_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1957)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_immediate = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()

overall_post_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1958)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_post = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()


overall_slope_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1950, 1956, 1958, 1963)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  group_by(acf_period, .draw) %>%
  summarise(pct_change_slope = ((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years) %>%
  distinct() %>%
  pivot_wider(names_from = c(acf_period),
              values_from = pct_change_slope) %>%
  mutate(ratio_annual_slope = `c. post-acf` / `a. pre-acf`)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'acf_period', '.draw'. You can override using the `.groups` argument.

Correlation between immediate effect and post effect of ACF


left_join(overall_immediate_draws, overall_post_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=pct_change_post)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  stat_regline_equation(label.x = 0.25, label.y = -0.25, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(labels = percent,
                     breaks = pretty_breaks(n = 5)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: ercentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Boundaries are posterior desnity intervals from 4000 draws") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

Correlation between immediate effect and change in slope


left_join(overall_immediate_draws, overall_slope_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  #stat_regline_equation(label.x = 0.25, label.y = 0.02, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(breaks = pretty_breaks(n = 5),
                     limits = c(0, 10)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: Percentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Points are draws from posteior distribution") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

7.3 Compared to counterfactual


overall_pulmonary_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_pulmonary_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`Joining with `by = join_by(.draw)`
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `across(c(pct_change:pct_change.upper), percent, accuracy = 0.1)`.
Caused by warning:
! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
Supply arguments directly to `.fns` through an anonymous function instead.

  # Previously
  across(a:b, mean, na.rm = TRUE)

  # Now
  across(a:b, \(x) mean(x, na.rm = TRUE))
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

Total pulmonary TB cases averted between 1958 and 1963


overall_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

8. Extra-pulmonary TB notifications

8.1 Fit the model


m_extrap_overall <- brm(
  extrapulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)),
                  data = mdata1,
                  family = poisson(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

 
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 0.2 seconds.
Chain 2 finished in 0.2 seconds.
Chain 3 finished in 0.2 seconds.
Chain 4 finished in 0.2 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.2 seconds.
Total execution time: 0.5 seconds.
summary(m_extrap_overall)
 Family: poisson 
  Links: mu = log 
Formula: extrapulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -7.90      0.05    -7.99    -7.81 1.00     2908     2532
y_num                         -0.09      0.01    -0.11    -0.07 1.00     2623     2183
acf_periodb.acf               -0.00      0.24    -0.48     0.48 1.00     2558     2487
acf_periodc.postMacf          -0.32      0.17    -0.64     0.01 1.00     2095     2415
y_num:acf_periodb.acf         -0.02      0.03    -0.08     0.04 1.00     2413     2577
y_num:acf_periodc.postMacf     0.02      0.02    -0.02     0.05 1.00     1711     2108

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_extrap_overall)

pp_check(m_extrap_overall, type='ecdf_overlay')

plot_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population, outcome=inc_ep_100k)
  
ggsave(here("figures/s6.png"), width=10)
Saving 10 x 4.51 in image

8.2 Summary of change

A. Percentage change in mortality, from 1956 to 1957 (i.e. immediate ACF effect)


summarise_change(model_data=mdata1, model = m_extrap_overall, population_denominator = total_population) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

8.3 Compared to counterfactual


overall_ep_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`Joining with `by = join_by(.draw)`
overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

Total extra pulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

9. Ward level model

9.1 Fit the model


mdata2 <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

(Note the denominator without institutionalised people and “shipping”!)

#weakly informative priors for multilevel model
basic_prior2 <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.1), class = b),
                 prior(cauchy(0,5), class="sd"))


ggplot(data = tibble(x = seq(from = 0, to = 250, by = 10)),
       aes(x = x, y = dgamma(x, shape = 0.5, rate = 0.01))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  scale_y_continuous(NULL, breaks = NULL) +
  coord_cartesian(xlim = c(0, 250)) +
  ggtitle(expression(brms~~gamma(0.5*", "*0.00001)~shape~prior))


winform_prior2 <- c(prior(normal(0, 1), class = Intercept),
                  prior(gamma(0.5, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))

m_pulmonary_ward_prior <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)),
                  data = mdata2,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior2,
                  save_pars = save_pars(all = TRUE),
                  sample_prior = "only",
                  backend = "cmdstanr",
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpvqbQUj/model-115da63cc2d2b.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.

-
0/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\
1 warning generated.

|

/
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

-

\

|

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 finished in 0.8 seconds.
Chain 2 finished in 0.8 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 0.9 seconds.
Chain 4 finished in 0.9 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.8 seconds.
Total execution time: 1.1 seconds.
conditional_effects(m_pulmonary_ward_prior)

NA
NA

Now fit the model with data

m_pulmonary_ward <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)),
                  data = mdata2,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior2,
                  backend = "cmdstanr")
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpvqbQUj/model-115da516879bf.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.

-
0/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'

\
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|
1 warning generated.

/

-
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

\

|

/

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 finished in 68.7 seconds.
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 69.8 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 70.2 seconds.
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 71.8 seconds.

All 4 chains finished successfully.
Mean chain execution time: 70.1 seconds.
Total execution time: 71.9 seconds.
summary(m_pulmonary_ward)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata2 (Number of observations: 518) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.26      0.04     0.20     0.34 1.00     1698     2316
sd(y_num)                                                 0.02      0.01     0.01     0.03 1.01     1217      978
sd(acf_periodb.acf)                                       0.08      0.05     0.00     0.18 1.00     1573     2064
sd(acf_periodc.postMacf)                                  0.13      0.08     0.01     0.30 1.00      939     1471
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.02 1.00     1612     2176
sd(y_num:acf_periodc.postMacf)                            0.01      0.01     0.00     0.03 1.01      576     1121
cor(Intercept,y_num)                                     -0.51      0.20    -0.81    -0.04 1.00     2566     2373
cor(Intercept,acf_periodb.acf)                           -0.28      0.33    -0.80     0.43 1.00     2987     2293
cor(y_num,acf_periodb.acf)                               -0.06      0.32    -0.64     0.58 1.00     5536     3410
cor(Intercept,acf_periodc.postMacf)                      -0.18      0.28    -0.67     0.41 1.00     4468     3115
cor(y_num,acf_periodc.postMacf)                           0.14      0.30    -0.45     0.70 1.00     3192     3324
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.10      0.32    -0.54     0.69 1.00     1909     2968
cor(Intercept,y_num:acf_periodb.acf)                     -0.27      0.33    -0.79     0.45 1.00     3493     2858
cor(y_num,y_num:acf_periodb.acf)                         -0.07      0.32    -0.66     0.57 1.00     5401     3217
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.09      0.34    -0.71     0.56 1.00     3930     3316
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.07      0.33    -0.58     0.67 1.00     3674     3348
cor(Intercept,y_num:acf_periodc.postMacf)                 0.02      0.31    -0.58     0.61 1.00     4641     2858
cor(y_num,y_num:acf_periodc.postMacf)                    -0.10      0.33    -0.69     0.57 1.00     1930     2364
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.07      0.33    -0.58     0.65 1.00     2736     3112
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.16      0.36    -0.81     0.55 1.00     1594     1728
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.07      0.33    -0.57     0.68 1.00     1848     2837

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.14      0.05    -6.24    -6.04 1.00     1155     1961
y_num                         -0.02      0.01    -0.03    -0.01 1.00     3100     3310
acf_periodb.acf                0.02      1.02    -1.99     1.98 1.00     4602     3119
acf_periodc.postMacf           0.05      0.11    -0.16     0.25 1.00     4476     2977
y_num:acf_periodb.acf          0.08      0.13    -0.16     0.33 1.00     4578     3148
y_num:acf_periodc.postMacf    -0.05      0.01    -0.07    -0.03 1.00     4216     3135

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    98.15     23.53    63.84   158.13 1.00     3107     2818

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_pulmonary_ward)

pp_check(m_pulmonary_ward, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.


plot_counterfactual(model_data = mdata2, model=m_pulmonary_ward, outcome = inc_100k, population_denominator = population_without_inst_ship, grouping_var = ward, ward)
  
ggsave(here("figures/s4.png"), width=10, height=12)

9.2 Summary of change

A. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)


ward_change <- summarise_change(model_data = mdata2, model = m_pulmonary_ward, population_denominator = population_without_inst_ship, grouping_var=ward) 
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ward_change %>%
  map(datatable)
$immediate_change

$post_change

$slope_change
NA

As a supplementary figure

  
ward_change$immediate_change %>%
  arrange(acf_inc100k_rr) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_inc100k_rr, ymin=acf_inc100k_rr.lower, ymax=acf_inc100k_rr.upper, 
                      x=fct_reorder(ward, acf_inc100k_rr),
                      colour = acf_inc100k_rr)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  coord_flip() +
  scale_colour_viridis_b(option = "D") +
  scale_y_continuous(limits = c(0.8,3.0)) +
  labs(x="",
       y="Relative posterior predicted case notification rate (per 100,000; 95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
ggsave(here("figures/s5.png"))
Saving 7.29 x 4.51 in image


ward_change$post_change %>%
  arrange(acf_inc100k_rr) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_inc100k_rr, ymin=acf_inc100k_rr.lower, ymax=acf_inc100k_rr.upper, 
                      x=fct_reorder(ward, acf_inc100k_rr),
                      colour = acf_inc100k_rr)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  coord_flip() +
  scale_colour_viridis_b(option = "D") +
  #scale_y_continuous(limits = c(0.8,3.0)) +
  labs(x="",
       y="Relative posterior predicted case notification rate (per 100,000; 95% UI)\nAfter ACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s6.png"))
Saving 7.29 x 4.51 in image

percentage change = (final value - initial value) / initial value


ward_change$slope_change %>%
  ggplot() +
  geom_pointrange(aes(y=pct_change_epred_overall , ymin=pct_change_lower_overall , ymax=pct_change_upper_overall ,
                      group=acf_period, colour=acf_period,
                      x = fct_reorder(ward, pct_change_epred_overall ))) +
  coord_flip() +
  scale_y_continuous(labels =percent) +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  #scale_y_continuous(limits = c(0.8,3.0)) +
  labs(title="Intervention effect of mass miniature chest X-ray in Glasgow",
       subtitle="By municipal ward",
       x="",
       y="Mean annual rate of change in case notification rate (95% CrI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

(Alternative figure - keep in for the minute)

Is there any correlation between immediate increase and a) post-intervention (1958) effect, and b) post intervention slope (1958-1963)


ward_cors <- ward_impact_out %>%
  select(ward, immediate_effect = acf_inc100k_rr,
               immediate_effect_lower = acf_inc100k_rr.lower,
               immediate_effect_upper = acf_inc100k_rr.upper) %>%
  right_join(
    ward_pulm_impact2 %>% 
      select(ward, post_effect = acf_inc100k_rr,
               post_effect_lower = acf_inc100k_rr.lower,
               post_effect_upper = acf_inc100k_rr.upper)
  ) %>%
  right_join(
    ward_pulm_impact3 %>%
      filter(acf_period=="c. post-acf") %>%
      select(ward, slope_effect = pct_change_epred_annual,
             slope_effect_lower = pct_change_lower_annual,
             slope_effect_upper = pct_change_upper_annual)
  )
Error in select(., ward, immediate_effect = acf_inc100k_rr, immediate_effect_lower = acf_inc100k_rr.lower,  : 
  object 'ward_impact_out' not found

Try a different way with the full distribution of posteriors

Correlation between immediate effect and post effect of ACF

Correlation between immediate effect and change in slope

Join these together with the overall estimates to make a single figure for showing impact

9.3 Compared to counterfactual


ward_counterf <- calcuate_counterfactual(model_data = mdata2, model=m_pulmonary_ward, population_denominator = population_without_inst_ship, grouping_var=ward)
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.Joining with `by = join_by(year, population_without_inst_ship, .draw)`Warning: Detected an unexpected many-to-many relationship between `x` and `y`.Joining with `by = join_by(.draw)`
ward_counterf %>%
  map(datatable)
$counter_post

$counter_post_overall
NA

Total pulmonary TB cases averted between 1958 and 1963

10. Age-sex model

10.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata3 <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

winform_prior3 <- c(prior(normal(0, 1), class = Intercept),
                  #prior(gamma(0.5, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))


m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata3,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior,
                  backend = "cmdstanr")
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpvqbQUj/model-115da1c751eb2.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.

/
0/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^

-

/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\
1 warning generated.

|

/
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

-

\

|

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 finished in 9.4 seconds.
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 9.7 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 9.6 seconds.
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 9.6 seconds.

All 4 chains finished successfully.
Mean chain execution time: 9.6 seconds.
Total execution time: 10.1 seconds.
summary(m_age_sex)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + (acf_period) * (age * sex) + (acf_period:y_num) * (age * sex) 
   Data: mdata3 (Number of observations: 224) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                                    4.47      0.08     4.31     4.62 1.00     2429     2931
y_num                                       -0.18      0.02    -0.22    -0.13 1.00     1390     2194
acf_periodb.acf                             -0.01      0.25    -0.49     0.47 1.00    10433     2887
acf_periodc.postMacf                         0.01      0.15    -0.30     0.30 1.00     4606     3010
age06_15                                     0.41      0.12     0.18     0.65 1.00     3070     2827
age16_25                                     1.56      0.11     1.34     1.79 1.00     2070     2939
age26_35                                     0.92      0.11     0.70     1.14 1.00     2537     2963
age36_45                                     0.24      0.12     0.02     0.47 1.00     3037     3317
age46_55                                    -0.34      0.13    -0.59    -0.08 1.00     2813     2851
age56_65                                    -0.64      0.13    -0.90    -0.38 1.00     3571     3404
age65P                                      -0.99      0.14    -1.26    -0.71 1.00     3427     2876
sexM                                         0.20      0.09     0.03     0.37 1.00     2440     2716
age06_15:sexM                               -0.29      0.15    -0.58     0.01 1.00     3885     3215
age16_25:sexM                               -0.31      0.14    -0.58    -0.03 1.00     2987     3222
age26_35:sexM                               -0.18      0.14    -0.45     0.09 1.00     2928     2855
age36_45:sexM                                0.16      0.14    -0.12     0.44 1.00     3311     3278
age46_55:sexM                                0.69      0.15     0.38     0.99 1.00     2993     2969
age56_65:sexM                                0.53      0.16     0.23     0.84 1.00     3329     3430
age65P:sexM                                  0.25      0.16    -0.06     0.56 1.00     3310     3450
acf_periodb.acf:age06_15                     0.02      0.25    -0.47     0.53 1.00     8378     2757
acf_periodc.postMacf:age06_15               -0.37      0.22    -0.81     0.08 1.00     6912     2822
acf_periodb.acf:age16_25                     0.03      0.25    -0.47     0.52 1.00     8484     2916
acf_periodc.postMacf:age16_25                0.23      0.20    -0.16     0.61 1.00     6331     3214
acf_periodb.acf:age26_35                     0.04      0.24    -0.44     0.52 1.00     9149     2749
acf_periodc.postMacf:age26_35                0.14      0.20    -0.26     0.54 1.00     6922     3253
acf_periodb.acf:age36_45                     0.05      0.25    -0.44     0.55 1.00     8346     3264
acf_periodc.postMacf:age36_45                0.10      0.20    -0.29     0.50 1.00     7240     3137
acf_periodb.acf:age46_55                     0.05      0.25    -0.44     0.54 1.00     8134     2763
acf_periodc.postMacf:age46_55                0.20      0.21    -0.20     0.59 1.00     5967     3717
acf_periodb.acf:age56_65                     0.04      0.24    -0.45     0.52 1.00     7812     2763
acf_periodc.postMacf:age56_65                0.05      0.21    -0.37     0.46 1.00     6009     2943
acf_periodb.acf:age65P                       0.04      0.25    -0.44     0.53 1.00     8029     3377
acf_periodc.postMacf:age65P                  0.11      0.22    -0.31     0.55 1.00     6647     3257
acf_periodb.acf:sexM                        -0.01      0.24    -0.47     0.45 1.00     9693     2911
acf_periodc.postMacf:sexM                    0.17      0.17    -0.18     0.51 1.00     5883     3083
y_num:acf_periodb.acf                       -0.06      0.05    -0.15     0.03 1.00     2624     2474
y_num:acf_periodc.postMacf                   0.00      0.03    -0.05     0.05 1.00     1687     2704
acf_periodb.acf:age06_15:sexM                0.01      0.24    -0.48     0.48 1.00     7743     2919
acf_periodc.postMacf:age06_15:sexM          -0.27      0.23    -0.72     0.18 1.00     8217     3108
acf_periodb.acf:age16_25:sexM                0.01      0.24    -0.47     0.48 1.00     8818     2623
acf_periodc.postMacf:age16_25:sexM           0.12      0.23    -0.32     0.58 1.00     7353     3074
acf_periodb.acf:age26_35:sexM                0.01      0.25    -0.49     0.50 1.00     9256     2639
acf_periodc.postMacf:age26_35:sexM           0.05      0.22    -0.39     0.50 1.00     7281     2607
acf_periodb.acf:age36_45:sexM                0.00      0.25    -0.49     0.48 1.00     8703     3032
acf_periodc.postMacf:age36_45:sexM           0.01      0.22    -0.43     0.45 1.00     7249     2773
acf_periodb.acf:age46_55:sexM                0.01      0.24    -0.47     0.49 1.00     9103     2587
acf_periodc.postMacf:age46_55:sexM           0.22      0.22    -0.21     0.65 1.00     6530     3109
acf_periodb.acf:age56_65:sexM                0.02      0.25    -0.47     0.53 1.00     9465     2697
acf_periodc.postMacf:age56_65:sexM           0.10      0.22    -0.33     0.53 1.00     7499     2951
acf_periodb.acf:age65P:sexM                  0.02      0.25    -0.46     0.50 1.00     9198     3071
acf_periodc.postMacf:age65P:sexM             0.12      0.23    -0.32     0.55 1.01     7371     2487
y_num:acf_perioda.preMacf:age06_15           0.06      0.03     0.00     0.13 1.00     1906     2589
y_num:acf_periodb.acf:age06_15               0.14      0.05     0.04     0.24 1.00     2804     2660
y_num:acf_periodc.postMacf:age06_15          0.08      0.02     0.03     0.12 1.00     4267     3359
y_num:acf_perioda.preMacf:age16_25           0.18      0.03     0.12     0.24 1.00     1422     2399
y_num:acf_periodb.acf:age16_25               0.25      0.05     0.15     0.34 1.00     2590     2847
y_num:acf_periodc.postMacf:age16_25          0.03      0.02    -0.02     0.07 1.00     3339     2925
y_num:acf_perioda.preMacf:age26_35           0.19      0.03     0.13     0.25 1.00     1637     2735
y_num:acf_periodb.acf:age26_35               0.30      0.05     0.21     0.40 1.00     2660     3000
y_num:acf_periodc.postMacf:age26_35          0.08      0.02     0.04     0.13 1.00     3778     3384
y_num:acf_perioda.preMacf:age36_45           0.17      0.03     0.11     0.23 1.00     1912     2636
y_num:acf_periodb.acf:age36_45               0.37      0.05     0.27     0.47 1.00     2570     2892
y_num:acf_periodc.postMacf:age36_45          0.12      0.02     0.07     0.16 1.00     3471     3230
y_num:acf_perioda.preMacf:age46_55           0.13      0.03     0.07     0.20 1.00     2070     2746
y_num:acf_periodb.acf:age46_55               0.37      0.05     0.27     0.47 1.00     2640     3015
y_num:acf_periodc.postMacf:age46_55          0.12      0.02     0.08     0.17 1.00     3329     3026
y_num:acf_perioda.preMacf:age56_65           0.09      0.04     0.01     0.16 1.00     2557     2631
y_num:acf_periodb.acf:age56_65               0.30      0.05     0.20     0.40 1.00     2875     2937
y_num:acf_periodc.postMacf:age56_65          0.12      0.02     0.07     0.17 1.00     3806     3521
y_num:acf_perioda.preMacf:age65P             0.10      0.04     0.02     0.17 1.00     2323     2883
y_num:acf_periodb.acf:age65P                 0.31      0.05     0.21     0.42 1.00     2557     2529
y_num:acf_periodc.postMacf:age65P            0.12      0.02     0.08     0.17 1.00     3806     3486
y_num:acf_perioda.preMacf:sexM               0.00      0.03    -0.05     0.06 1.00     1427     2161
y_num:acf_periodb.acf:sexM                  -0.06      0.06    -0.17     0.05 1.00     1911     2495
y_num:acf_periodc.postMacf:sexM             -0.04      0.02    -0.08     0.01 1.00     2451     2376
y_num:acf_perioda.preMacf:age06_15:sexM     -0.03      0.04    -0.11     0.06 1.00     2333     2818
y_num:acf_periodb.acf:age06_15:sexM          0.04      0.06    -0.08     0.17 1.00     2246     2948
y_num:acf_periodc.postMacf:age06_15:sexM     0.06      0.03     0.00     0.12 1.00     3715     2984
y_num:acf_perioda.preMacf:age16_25:sexM     -0.05      0.04    -0.13     0.02 1.00     1797     2555
y_num:acf_periodb.acf:age16_25:sexM          0.04      0.06    -0.07     0.16 1.00     2165     2572
y_num:acf_periodc.postMacf:age16_25:sexM     0.01      0.03    -0.04     0.07 1.00     2953     3168
y_num:acf_perioda.preMacf:age26_35:sexM     -0.04      0.04    -0.11     0.04 1.00     1870     2546
y_num:acf_periodb.acf:age26_35:sexM          0.05      0.06    -0.07     0.17 1.00     2149     2476
y_num:acf_periodc.postMacf:age26_35:sexM     0.01      0.03    -0.04     0.07 1.00     3056     2807
y_num:acf_perioda.preMacf:age36_45:sexM      0.00      0.04    -0.07     0.08 1.00     2046     2557
y_num:acf_periodb.acf:age36_45:sexM          0.03      0.06    -0.09     0.15 1.00     2159     2970
y_num:acf_periodc.postMacf:age36_45:sexM     0.01      0.03    -0.04     0.07 1.00     3192     2893
y_num:acf_perioda.preMacf:age46_55:sexM      0.09      0.04     0.00     0.17 1.00     2176     2834
y_num:acf_periodb.acf:age46_55:sexM          0.07      0.06    -0.04     0.19 1.00     2182     2850
y_num:acf_periodc.postMacf:age46_55:sexM     0.01      0.03    -0.04     0.07 1.00     2864     2889
y_num:acf_perioda.preMacf:age56_65:sexM      0.17      0.04     0.09     0.26 1.00     2469     2962
y_num:acf_periodb.acf:age56_65:sexM          0.16      0.06     0.04     0.28 1.00     2273     3150
y_num:acf_periodc.postMacf:age56_65:sexM     0.09      0.03     0.04     0.15 1.00     3443     3481
y_num:acf_perioda.preMacf:age65P:sexM        0.15      0.05     0.07     0.24 1.00     2348     3140
y_num:acf_periodb.acf:age65P:sexM            0.19      0.06     0.07     0.31 1.00     2208     2439
y_num:acf_periodc.postMacf:age65P:sexM       0.09      0.03     0.03     0.15 1.00     2998     3054

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    98.38     33.81    52.32   180.75 1.00     1401     2192

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_age_sex)

pp_check(m_age_sex, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

Summarise posterior

ggsave(here("figures/s7.png"), height=10)
Saving 7 x 10 in image

10.2 Summary of impact of intervention

  1. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)

nd <- mdata3 %>%
  filter(year %in% c(1956:1957)) %>%
  select(acf_period, y_num, age, sex)


age_sex_impact_out <- 
  add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
         post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 
Warning: `cols` is now required when using `unnest()`.
ℹ Please use `cols = c(`a. pre-acf`, `b. acf`)`.
age_sex_impact_out %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
`mutate_if()` ignored the following grouping variables:
  
f3a <- age_sex_impact_out %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
  
  1. Change from pre-ACF period (1956), to first year post-ACF (1958)

nd <- mdata3 %>%
  filter(year %in% c(1956,1958)) %>%
  select(acf_period, y_num, age, sex)

#Do it with calculating incidence, then sumamrising.
age_sex_impact2 <-add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
        post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 
Warning: `cols` is now required when using `unnest()`.
ℹ Please use `cols = c(`a. pre-acf`, `c. post-acf`)`.
age_sex_impact2 %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
`mutate_if()` ignored the following grouping variables:
f3b <- age_sex_impact2 %>%  
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  1. Change in slope (i.e. difference in mean annual case notification rate pre-Intervention vs. post-intervention, by ward)

age_sex_impact3 <- mdata3 %>%
  select(year, year2, y_num, acf_period, cases, age, sex) %>%
  filter(year!=1957) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year, age, sex, acf_period) %>%
  mean_qi(.epred) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  summarise(pct_change_epred_overall = (((last(.epred) - first(.epred))/first(.epred))),
            pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
            pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
    
            pct_change_epred_annual = (((last(.epred) - first(.epred))/first(.epred))/n_years),
            pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
            pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
            .by = c(acf_period, age, sex)) %>%
  distinct()
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
age_sex_impact3 %>%
  mutate_if(is.double, percent) %>%
  datatable()

f3c <- age_sex_impact3 %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
    geom_pointrange(aes(y=pct_change_epred_annual, ymin=pct_change_lower_annual, ymax=pct_change_upper_annual, group=acf_period, 
                      x=age,
                      colour = acf_period), size=0.1) +
  scale_y_continuous(labels =percent) +
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  labs(x="",
       y="Mean annual rate of change in case notification rate (95% UI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

f3c

Join together for Figure 2.


(f3a / f3b / f3c) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f3.png"), height=12)
Saving 7.29 x 12 in image

10.3 Compared to counterfactual

counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 
Joining with `by = join_by(age, sex, .draw)`

11. Division-level model

(Very much a work in progress!)

plot_counterfactual(model=m_pulmonary_division_prior, model_data=mdata3, population_denominator = population_without_inst_ship, outcome = cases, grouping_var = division, division) + scale_y_log10()
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.

12. Counterfactual table

Make a table of counterfactual effects for the manuscript

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShnZ3NuKQoKYGBgCgojIyMjIDEuMiBIZWxwZXIgZnVuY3Rpb25zCgpGdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZSB0aHJvdWdob3V0IHRoZSBzY3JpcHQKCmBgYHtyfQojbGFiZWxsZXIgZm9yIHllYXJzCnllYXJfbGFiZWxzIDwtIGMoMTk1MDoxOTYzKQoKI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCmFjZl9zdGFydCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTAzLTExIikpCmFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKCmBgYAoKRnVuY3Rpb24gZm9yIGNvdW50ZXJmYWN0dWFsIHBsb3RzCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwgPC0gZnVuY3Rpb24obW9kZWxfZGF0YSwgbW9kZWwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IsIG91dGNvbWUsIGdyb3VwaW5nX3Zhcj1OVUxMLCAuLi4pewogIAogICNsYWJlbGxlciBmb3IgeWVhcnMKICB5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiAgI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKICAjU2VnbWVudCBmb3IgZ3JhcGhzIHRvIG1hdGNoIEFDRiBwZXJpb2QKICBhY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQogIGFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKICBzdW1tYXJ5IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7b3V0Y29tZX19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVkaWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgICAuZXByZWRfaW5jLmxvd2VyID0gLmVwcmVkLmxvd2VyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAlPiUKICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKCgoKICAjY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQogIAogIGNvdW50ZXJmYWN0IDwtCiAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCB7e291dGNvbWV9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVkaWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQogIAoKCiAgI3Bsb3QgdGhlIGludGVydmVudGlvbiBlZmZlY3QKcCA8LSBzdW1tYXJ5ICU+JQogICAgZHJvcGxldmVscygpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9yaWJib24oZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogICAgZ2VvbV9wb2ludChkYXRhID0ge3ttb2RlbF9kYXRhfX0sIGFlcyh5PXt7b3V0Y29tZX19LCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgICB0aGVtZV9nZ2Rpc3QoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIikgKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogICAgbGFicygKICAgICAgeCA9ICJZZWFyIiwKICAgICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGFuZ2xlID0gOTAsIGhqdXN0PTEsIHZqdXN0PTAuNSksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgZ3VpZGVzKHNoYXBlPSJub25lIikKCiAgICBmYWNldF92YXJzIDwtIHZhcnMoLi4uKQoKICBpZiAobGVuZ3RoKGZhY2V0X3ZhcnMpICE9IDApIHsKICAgIHAgPC0gcCArIGZhY2V0X3dyYXAoZmFjZXRfdmFycykKICB9CiAgcAoKfQoKYGBgCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgIG1lYXN1cmVzIG9mIGNoYW5nZSBvdmVyIHRpbWUKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZSA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewoKICAjYS4gaW1tZWRpYXRlIGNoYW5nZQogIG5kX2ltbWVkaWF0ZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICAgIHNlbGVjdChhY2ZfcGVyaW9kLCB5ZWFyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pCgogICNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIGltbWVkaWF0ZV9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX2ltbWVkaWF0ZSkgJT4lCiAgICBtdXRhdGUoZXByZWRfaW5jMTAwayA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSkgJT4lCiAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtdXRhdGUoYWNmX2luYzEwMGtfZGlmZiA9IGxhc3QoZXByZWRfaW5jMTAwayktZmlyc3QoZXByZWRfaW5jMTAwayksCiAgICAgICAgICAgYWNmX2luYzEwMGtfcnIgPSBsYXN0KGVwcmVkX2luYzEwMGspL2ZpcnN0KGVwcmVkX2luYzEwMGspKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShhY2ZfaW5jMTAwa19kaWZmLCBhY2ZfaW5jMTAwa19ycikgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIkltbWVkaWF0ZSBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNiLiBwb3N0LUFDRiBjaGFuZ2UKICBuZF9wb3N0IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogICAgc2VsZWN0KGFjZl9wZXJpb2QsIHllYXIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkKCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX3Bvc3QpICU+JQogICAgbXV0YXRlKGVwcmVkX2luYzEwMGsgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0pICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbXV0YXRlKGFjZl9pbmMxMDBrX2RpZmYgPSBsYXN0KGVwcmVkX2luYzEwMGspLWZpcnN0KGVwcmVkX2luYzEwMGspLAogICAgICAgICAgIGFjZl9pbmMxMDBrX3JyID0gbGFzdChlcHJlZF9pbmMxMDBrKS9maXJzdChlcHJlZF9pbmMxMDBrKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBncm91cF9ieSh7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoYWNmX2luYzEwMGtfZGlmZiwgYWNmX2luYzEwMGtfcnIpICU+JQogICAgbXV0YXRlKGNoYW5nZSA9ICJQb3N0LUFDRiBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNjLiBjaGFuZ2UgaW4gc2xvcGUgcG9zdCB2cy4gcHJlLUFDRgogIHNsb3BlX2NoYW5nZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGZpbHRlcih5ZWFyIT0xOTU3KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kLCApICU+JQogICAgbWVhbl9xaShpbmNfMTAwaykgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWMoYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkpICU+JQogICAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpKSwKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkpLAogICAgICAKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpL25feWVhcnMpLAogICAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkvbl95ZWFycyksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9hbm51YWwgPSAoKChsYXN0KC51cHBlcikgLSBmaXJzdCgudXBwZXIpKS9maXJzdCgudXBwZXIpKS9uX3llYXJzKSwKICAgICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pKSAlPiUKICAgIGRpc3RpbmN0KCkgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIlNsb3BlIGNoYW5nZSIpCgogIGxzdChpbW1lZGlhdGVfY2hhbmdlLCBwb3N0X2NoYW5nZSwgc2xvcGVfY2hhbmdlKQogICAgCn0KCmBgYAoKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBkaWZmZXJlbmNlIGZyb20gY291bnRlcmZhY3R1YWwKCmBgYHtyfQpjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewogIAogICNlZmZlY3QgdnMuIGNvdW50ZXJmYWN0dWFsCiAgY291bnRlcmZhY3QgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBncm91cF9ieSguZHJhdywgeWVhciwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkgJT4lCiAgICAgIG11dGF0ZSguZXByZWRfaW5jX2NvdW50ZXJmID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwgLmVwcmVkX2NvdW50ZXJmPS5lcHJlZCkgICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIC5kcmF3LCAuZXByZWRfY291bnRlcmYsIC5lcHJlZF9pbmNfY291bnRlcmYpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpICU+JQogICAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCAuZHJhdywgLmVwcmVkLCAuZXByZWRfaW5jKSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZAogICAgY291bnRlcmZhY3Rfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCAuZHJhdywgLmVwcmVkKSAgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAlPiUKICAgICAgbXV0YXRlKHllYXIgPSAiT3ZlcmFsbCAoMTk1OC0xOTYzKSIpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkpICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKY291bnRlcl9wb3N0IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0LCBwb3N0X2NoYW5nZSkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZiwKICAgICAgICAgICBkaWZmX2luYzEwMGsgPSAuZXByZWRfaW5jIC0gLmVwcmVkX2luY19jb3VudGVyZiwKICAgICAgICAgICBycl9pbmMxMDBrID0gLmVwcmVkX2luYy8uZXByZWRfaW5jX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlLCBkaWZmX2luYzEwMGssIHJyX2luYzEwMGspICU+JQogICAgdW5ncm91cCgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdF9vdmVyYWxsLCBwb3N0X2NoYW5nZV9vdmVyYWxsKSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCmxzdChjb3VudGVyX3Bvc3QsIGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKfQoKCgpgYGAKCkZ1bmN0aW9uIGZvciB0aWR5aW5nIHVwIGNvdW50ZXJmYWN0dWFscyAobW9zdGx5IGZvciBtYWtpbmcgbmljZSB0YWJsZXMpCgpgYGB7cn0KCnRpZHlfY291bnRlcmZhY3R1YWxzIDwtIGZ1bmN0aW9uKGRhdGEpewogIGRhdGEgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH0gKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX0gKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIiksCiAgICAgICAgICAgIGRpZmZfaW5jID0gZ2x1ZTo6Z2x1ZSgie2RpZmZfaW5jMTAwa30gKHtkaWZmX2luYzEwMGsubG93ZXJ9IHRvIHtkaWZmX2luYzEwMGsudXBwZXJ9KSIpLAogICAgICAgICAgICBycl9pbmMgPSBnbHVlOjpnbHVlKCJ7cnJfaW5jMTAwa30gKHtycl9pbmMxMDBrLmxvd2VyfSB0byB7cnJfaW5jMTAway51cHBlcn0pIikpCn0KCgp0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIGZ1bmN0aW9uKGRhdGEpewogIGRhdGEgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfSAoe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfSAoe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSkKfQoKYGBgCgoKCiMjIyAyLiBEYXRhCgpJbXBvcnQgZGF0YXNldHMgZm9yIGFuYWx5c2lzCgojIyMjIDIuMSBTaGFwZWZpbGVzCgpNYWtlIGEgbWFwIG9mIEdsYXNnb3cgd2FyZHMKCmBgYHtyfQoKZ2xhc2dvd193YXJkc18xOTUxIDwtIHN0X3JlYWQoaGVyZSgibWFwcGluZy9nbGFzZ293X3dhcmRzXzE5NTEuZ2VvanNvbiIpKQoKYGBgCgpgYGB7cn0KCiNyZWFkIGluIFNjb3RsYW5kIGJvdW5kYXJ5CnNjb3RsYW5kIDwtIHN0X3JlYWQoaGVyZSgibWFwcGluZy9TY290bGFuZF9ib3VuZGFyeS9TY290bGFuZCBib3VuZGFyeS5zaHAiKSkKCgoKI21ha2UgYSBib3VuZGluZyBib3ggZm9yIEdsYXNnb3cKYmJveCA8LSBzdF9iYm94KGdsYXNnb3dfd2FyZHNfMTk1MSkgfD4gc3RfYXNfc2ZjKCkKCiNwbG90IHNjb3RsYW4gd2l0aCBhIGJvdW5kaW5nIGJveCBhcm91bmQgdGhlIENpdHkgb2YgR2xhc2dvdwpzY290bGFuZF93aXRoX2Jib3ggPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHNjb3RsYW5kLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgZ2VvbV9zZihkYXRhID0gYmJveCwgY29sb3VyID0gIiNDNjBDMzAiLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEsIGxpbmV3aWR0aCA9IDAuNSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQUY3RkEiLCBzaXplID0gMC4zKSkKCgojcGxvdCB0aGUgd2FyZHMKI25vdGUgd2UgdGlkeSB1cCBzb21lIG5hbWVzIHRvIGZpdCBvbiBtYXAKZ2xhc2dvd193YXJkX21hcCA8LSBnbGFzZ293X3dhcmRzXzE5NTEgJT4lCiAgbXV0YXRlKHdhcmQgPSBjYXNlX3doZW4od2FyZD09IlNoZXR0bGVzdG9uIGFuZCBUb2xsY3Jvc3MiIH4gIlNoZXR0bGVzdG9uIGFuZFxuVG9sbGNyb3NzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iUGFydGljayAoV2VzdCkiIH4gIlBhcnRpY2tcbihXZXN0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09IlBhcnRpY2sgKEVhc3QpIiB+ICJQYXJ0aWNrXG4oRWFzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJOb3J0aCBLZWx2aW4iIH4gIk5vcnRoXG5LZWx2aW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJLaW5uaW5nIFBhcmsiIH4gIktpbm5pbmdcblBhcmsiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiB3YXJkKSkgJT4lCiAgCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9ZGl2aXNpb24pKSArCiAgZ2VvbV9zZl9sYWJlbChhZXMobGFiZWwgPSB3YXJkKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siLCBmYW1pbHkgPSAiU2Vnb2UgVUkiKSArCiAgI3NjYWxlX2NvbG91cl9pZGVudGl0eSgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJDaXR5IG9mIEdsYXNnb3cgRGl2aXNpb24iKSArCiAgdGhlbWVfZ3JleShiYXNlX2ZhbWlseSA9ICJTZWdvZSBVSSIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSIiLAogICAgICAgZmlsbD0iRGl2aXNpb24iKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbnRpcXVld2hpdGUiLCBzaXplID0gMC4zKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk3OCIpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41LCB0aXRsZS50aGVtZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpKSArCiAgc2NhbGViYXIoZ2xhc2dvd193YXJkc18xOTUxLCBkaXN0ID0gMiwgZGlzdF91bml0ID0gImttIiwKICAgICAgICAgICAgIHRyYW5zZm9ybSA9IFRSVUUsIG1vZGVsID0gIldHUzg0IiwgbG9jYXRpb249ImJvdHRvbWxlZnQiKQoKI2FkZCB0aGUgbWFwIG9mIHNjb3RsYW5kIGFzIGFuIGluc2V0CmdsYXNnb3dfd2FyZF9tYXAgKyBpbnNldF9lbGVtZW50KHNjb3RsYW5kX3dpdGhfYmJveCwgMC43NSwgMCwgMSwgMC40KQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczEucG5nIiksIGhlaWdodD0xMCwgd2lkdGggPSAxMikKCgpgYGAKCgoKIyMjIDMuIERlbm9taW5hdG9ycwoKTG9hZCBpbiB0aGUgZGF0YXNldHMgZm9yIGRlbm9ub21pYXRvcnMsIGFuZCBjaGVjayBmb3IgY29uc2lzdGVuY3kuCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJvdmVyYWxsX3BvcHVsYXRpb24iKQoKb3ZlcmFsbF9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50Cm92ZXJhbGxfcG9wcyA8LSBvdmVyYWxsX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKCk5vdGUsIHdlIGhhdmUgdGhyZWUgcG9wdWxhdGlvbiBlc3RpbWF0ZXM6CgoxLiBQb3B1bGF0aW9uIHdpdGhvdXQgaW5zdGl0dXRpb25hbGlzZWQgcGVvcGxlIG9yIHBlb3BsZSBpbiBzaGlwcGluZwoyLiBQb3B1bGF0aW9uIGluIGluc3RpdHV0aW9ucwozLiBQb3B1bGF0aW9uIGluIHNoaXBwaW5nCgooUG9wdWxhdGlvbiBpbiBzaGlwcGluZyBpcyBlc3RpbWF0ZWQgZnJvbSB0aGUgMTk1MSBjZW5zdXMsIHNvIGlzIHRoZSBzYW1lIGZvciBtb3N0IHllYXJzKQoKIyMjIyAzLjEgT3ZlcmFsbCBwb3B1bGF0aW9uCgpGaXJzdCwgcGxvdCB0aGUgdG90YWwgcG9wdWxhdGlvbgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyKSwgYWxwaGE9MC41LCBjb2xvdXIgPSAibWVkaXVtc2VhZ3JlZW4iLCBmaWxsPSJtZWRpdW1zZWFncmVlbiIpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIpLCBjb2xvdXIgPSAibWVkaXVtc2VhZ3JlZW4iKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHRvdGFsIHBvcHVsYXRpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpCgoKYGBgCgpOb3cgdGhlIHBvcHVsYXRpb24gZXhjbHVkaW5nIGluc3RpdHV0aW9uYWxpc2VkIGFuZCBzaGlwcGluZyBwb3B1bGF0aW9uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHg9eWVhcjIpLCBhbHBoYT0wLjUsIGNvbG91ciA9ICJwdXJwbGUiLCBmaWxsPSJwdXJwbGUiKSArCiAgZ2VvbV9wb2ludChhZXMoeT1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB4PXllYXIyKSwgY29sb3VyID0gInB1cnBsZSIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogcG9wdWxhdGlvbiBleGNsdWRpbmcgaW5zdGl0dXRpb25hbGlzZWQgYW5kIHNoaXBwaW5nIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKQoKCmBgYAoKIyMjIyAzLjIgUG9wdWxhdGlvbiBieSBXYXJkCgpUaGVyZSBhcmUgNSBEaXZpc2lvbnMgY29udGFpbmluZyAzNyBXYXJkcyBpbiB0aGUgR2xhc2dvdyBDb3Jwb3JhdGlvbiwgd2l0aCBjb25zaXN0ZW50IGJvdW5kYXJpZXMgb3ZlciB0aW1lLgoKYGBge3J9CiNsb29rLXVwIHRhYmxlIGZvciBkaXZpc2lvbnMgYW5kIHdhcmRzCndhcmRfbG9va3VwIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImRpdmlzaW9uc193YXJkcyIpCgoKd2FyZF9wb3BzIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gIndhcmRfcG9wdWxhdGlvbiIpCgp3YXJkX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKd2FyZF9wb3BzIDwtIHdhcmRfcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCiNHZXQgdGhlIERpdmlzaW9uIHBvcHVsYXRpb24KZGl2aXNpb25fcG9wcyA8LSB3YXJkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoZGl2aXNpb24sIHllYXIpICU+JQogIHN1bW1hcmlzZShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwID0gc3VtKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGluc3RpdHV0aW9ucyA9IHN1bShpbnN0aXR1dGlvbnMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHNoaXBwaW5nID0gc3VtKHNoaXBwaW5nLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB0b3RhbF9wb3B1bGF0aW9uID0gc3VtKHRvdGFsX3BvcHVsYXRpb24sIG5hLnJtID0gVFJVRSkpCgpkaXZpc2lvbl9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKUGxvdCB0aGUgb3ZlcmFsbCBwb3B1bGF0aW9uIGJ5IERpdmlzaW9uIGFuZCBXYXJkCgpgYGB7cn0KCmRpdmlzaW9uX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uLCBmaWxsPWRpdmlzaW9uKSwgYWxwaGE9MC44KSArCiAgZ2VvbV9wb2ludChhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24pKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4pICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lID0gIiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiB0b3RhbCBwb3B1bGF0aW9uIGJ5IERpdmlzaW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKYGBgCgpgYGB7cn0KCndhcmRfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbiwgZmlsbD1kaXZpc2lvbiksIGFscGhhPTAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4sIG5jb2w9NikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWU9IkRpdmlzaW9uIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICJEaXZpc2lvbiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDaXR5OiB0b3RhbCBwb3B1bGF0aW9uIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MyLnBuZyIpLCBoZWlnaHQ9MTAsIHdpZHRoPTEyKQoKYGBgCgpBcHByb3hpbWF0ZWx5LCBob3cgbWFueSBwZXJzb24teWVhcnMgb2YgZm9sbG93LXVwIGRvIHdlIGhhdmU/CgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyh5ZWFyLCBsZW5ndGgsIC5uYW1lcyA9ICJ5ZWFycyIpLAogICAgICAgICAgICBhY3Jvc3MoYyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB0b3RhbF9wb3B1bGF0aW9uKSwgc3VtKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5kb3VibGUpLCBjb21tYSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpDaGFuZ2UgaW4gcG9wdWxhdGlvbiBieSB3YXJkCgpgYGB7cn0KCndhcmRfcG9wcyAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9wb3AgPSAobGFzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSAtIGZpcnN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKS9maXJzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSkgJT4lCiAgbXV0YXRlKHBjdF9jaGFuZ2VfcG9wID0gcGVyY2VudChwY3RfY2hhbmdlX3BvcCkpICU+JQogIGFycmFuZ2UocGN0X2NoYW5nZV9wb3ApICU+JQogIGRhdGF0YWJsZSgpCiAgCgoKYGBgCgoKIyMjIyAzLjMgUG9wdWxhdGlvbiBieSBhZ2UgYW5kIHNleAoKYGBge3J9CgphZ2Vfc2V4IDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImFnZV9zZXhfcG9wdWxhdGlvbiIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhtYWxlLCBmZW1hbGUpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJzZXgiKQoKI2NvbGxhcHNlIGRvd24gdG8gc21hbGxlciBhZ2UgZ3JvdXBzIHRvIGJlIG1hbmFnZWFibGUKYWdlX3NleCA8LSBhZ2Vfc2V4ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZSA9PSAiMCB0byA0IiB+ICIwMCB0byAwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjUgdG8gOSIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxMCB0byAxNCIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxNSB0byAxOSIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyMCB0byAyNCIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyNSB0byAyOSIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzMCB0byAzNCIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzNSB0byAzOSIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0MCB0byA0NCIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0NSB0byA0OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1MCB0byA1NCIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1NSB0byA1OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICI2MCAmIHVwIikpICU+JQogIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4KSAlPiUKICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUKICB1bmdyb3VwKCkKCgoKbV9hZ2Vfc2V4IDwtIGxtKHZhbHVlIH4gc3BsaW5lczo6bnMoeWVhciwga25vdHMgPSAzKSphZ2Uqc2V4LCBkYXRhID0gYWdlX3NleCkKCnN1bW1hcnkobV9hZ2Vfc2V4KQoKYWdlX2xldmVscyA8LSBhZ2Vfc2V4ICU+JSBzZWxlY3QoYWdlKSAlPiUgZGlzdGluY3QoKSAlPiUgcHVsbCgpIAoKYWdlX3NleF9uZCA8LSAKICBjcm9zc2luZygKICAgIGFnZT1hZ2VfbGV2ZWxzLAogICAgc2V4PWMoIm1hbGUiLCAiZmVtYWxlIiksCiAgICB5ZWFyID0gMTk1MDoxOTYzCiAgKQoKcHJlZF9wb3BzIDwtIGFnZV9zZXhfbmQgJT4lIG1vZGVscjo6YWRkX3ByZWRpY3Rpb25zKG1fYWdlX3NleCkKCnByZWRfcG9wcyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wcmVkLCBjb2xvdXI9YWdlKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoc2V4fi4pICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoMCwgMTI1MDAwKSkKCiNIb3cgd2VsbCBkbyB0aGV5IG1hdGNoIHVwIHdpdGggb3VyIG92ZXJhbGwgcG9wdWxhdGlvbnM/CnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2Uoc3VtX3ByZWRfcG9wID0gc3VtKHByZWQpKSAlPiUKICByaWdodF9qb2luKG92ZXJhbGxfcG9wcykgJT4lCiAgc2VsZWN0KHllYXIsIHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvdXI9bmFtZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSwgbGltaXRzID0gYyg4MDAwMDAsIDEyNTAwMDApKQoKcHJlZF9wb3BzICU+JQogIGdyb3VwX2J5KHllYXIsIHNleCkgJT4lCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShwcmVkKSkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHNleF9yYXRpbyA9IGZpcnN0KHN1bSkvbGFzdChzdW0pKQpgYGAKClBvcHVsYXRpb24gcHlyYW1pZHMKCmBgYHtyfQoKbGFiZWxfYWJzIDwtIGZ1bmN0aW9uKHgpIHsKICBjb21tYShhYnMoeCkpCn0KCgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZSh5ZWFyX3BvcCA9IHN1bShwcmVkKSwKICAgICAgICAgYWdlX3NleF9wY3QgPSBwZXJjZW50KHByZWQveWVhcl9wb3AsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0ibWFsZSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJmZW1hbGUiIH4gIkZlbWFsZSIpKSAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IGFnZSwgZmlsbCA9IHNleCwgCiAgICAgICAgeSA9IGlmZWxzZSh0ZXN0ID0gc2V4ID09ICJGZW1hbGUiLHllcyA9IC1wcmVkLCBubyA9IHByZWQpKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBhZ2Vfc2V4X3BjdCksCiAgICAgICAgICAgIHBvc2l0aW9uPSBwb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBjb2xvdXI9IndoaXRlIiwgc2l6ZT0yLjUpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfYWJzKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibWVkaXVtc2VhZ3JlZW4iLCAicHVycGxlIiksIG5hbWU9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0ID0gMSwgdmp1c3Q9MC41KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSIiLCB5PSIiKSAKCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMy5wbmciKSwgd2lkdGg9MTApCgoKYGBgCgpOb3QgcGVyZmVjdCwgYnV0IHJlc29uYWJseSBnb29kLiBCdXQgYWhoaGhoLi4uIHRoZSBhZ2UgZ3JvdXBzIGRvbid0IGFsaWduIHdpdGggdGhlIGNhc2Ugbm90aWZpY2F0aW9uIGFnZSBncm91cHMhIENvbWUgYmFjayB0byB0aGluayBhYm91dCB0aGlzIGxhdGVyLgoKCiMjIyA0LiBUdWJlcmN1bG9zaXMgY2FzZXMKCkltcG9ydCB0aGUgdHViZXJjdWxvc2lzIGNhc2VzIGRhdGFzZXQKCgojIyMjIDQuMSBPdmVyYWxsIG5vdGlmaWNhdGlvbnMKCk92ZXJhbGwsIGJ5IHllYXIuCgpgYGB7cn0KCmNhc2VzX2J5X3llYXIgPC0gcmVhZF94bHN4KCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJieV95ZWFyIikKCmNhc2VzX2J5X3llYXIlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfeWVhciA8LSBjYXNlc19ieV95ZWFyICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKYGBgCgpQbG90IHRoZSBvdmVyYWxsIG51bWJlciBvZiBjYXNlIG5vdGlmaWVkIHBlciB5ZWFyLCBieSBwdWxtb25hcnkgYW5kIGV4dHJhIHB1bG1vbmFyeSBjbGFzc2lmaWNhdGlvbi4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciAlPiUKICBzZWxlY3QoLXRvdGFsX25vdGlmaWNhdGlvbnMsIC15ZWFyKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMocHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMsIGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAicHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAibm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zIiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT12YWx1ZSwgeD15ZWFyMiwgZ3JvdXAgPSBuYW1lLCBmaWxsPW5hbWUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgCgpgYGAKCiMjIyMgNC4yIE5vdGlmaWNhdGlvbnMgYnkgRGl2aXNpb24KClJlYWQgaW4gdGhlIGRhdGFzZXRzIGFuZCBtZXJnZSB0b2dldGhlci4KCmBgYHtyfQoKI2xpc3QgYWxsIHRoZSBzaGVldHMKYWxsX3NoZWV0cyA8LSBleGNlbF9zaGVldHMoIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIpCgojZ2V0IHRoZSB3YXJkIHNoZWV0cwp3YXJkX3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiYnlfd2FyZCIsIHZhbHVlKSkgJT4lCiAgcHVsbCh2YWx1ZSkKCgpjYXNlc19ieV93YXJkX3NleF95ZWFyIDwtIG1hcF9kZih3YXJkX3NoZWV0cywgfnJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAuKSkKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpBZ2dyZWdhdGUgdG9nZXRoZXIgdG8gY2FzZSBjYXNlcyBieSBkaXZpc2lvbgoKYGBge3J9CgpjYXNlc19ieV9kaXZpc2lvbiA8LSBjYXNlc19ieV93YXJkX3NleF95ZWFyICU+JQogIGxlZnRfam9pbih3YXJkX2xvb2t1cCkgJT4lCiAgZ3JvdXBfYnkoZGl2aXNpb24sIHllYXIsIHRiX3R5cGUpICU+JQogIHN1bW1hcmlzZShjYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CmNhc2VzX2J5X2RpdmlzaW9uIDwtIGNhc2VzX2J5X2RpdmlzaW9uICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICB1bmdyb3VwKCkKCmNhc2VzX2J5X2RpdmlzaW9uICAlPiUKICBzZWxlY3QoLXllYXIyKSAlPiUKICBzZWxlY3QoeWVhciwgZXZlcnl0aGluZygpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKY2FzZXNfYnlfZGl2aXNpb24gJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWNhc2VzLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmBgYAoKIyMjIyA0LjMgTm90aWZpY2F0aW9ucyBieSB3YXJkCgpgYGB7cn0KCgpjYXNlc19ieV93YXJkIDwtIGNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgZ3JvdXBfYnkod2FyZCwgeWVhciwgdGJfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNhc2VzID0gc3VtKGNhc2VzLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkKCmNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBzZWxlY3QoeWVhciwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfd2FyZCA8LSBjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC44KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKHdhcmR+Liwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCmBgYAoKIyMjIyA0LjQgTm90aWZpY2F0aW9ucyBieSBhZ2UgYW5kIHNleAoKQXMgd2UgZG9uJ3QgaGF2ZSBkZW5vbWluYXRvcnMsIHdlIHdpbGwganVzdCBtb2RlbCB0aGUgY2hhbmdlIGluIGNvdW50cy4KCmBgYHtyfQoKI2xpc3QgYWxsIHRoZSBzaGVldHMKYWxsX3NoZWV0cyA8LSBleGNlbF9zaGVldHMoIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIpCgojZ2V0IHRoZSB3YXJkIHNoZWV0cwphZ2Vfc2V4X3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiYnlfYWdlX3NleCIsIHZhbHVlKSkgJT4lCiAgcHVsbCh2YWx1ZSkKCgpjYXNlc19ieV9hZ2Vfc2V4IDwtIG1hcF9kZihhZ2Vfc2V4X3NoZWV0cywgfnJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAuKSkKCmNhc2VzX2J5X2FnZV9zZXggJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKCgoKIyMjIDUgVEIgaW5jaWRlbmNlCgojIyMjIDUuMSBPdmVyYWxsIFRCIGluY2lkZW5jZQoKTm93IGNhbGN1bGF0ZSBpbmNpZGVuY2UgcGVyIDEwMCwwMDAgcG9wdWxhdGlvbgoKTWVyZ2UgdGhlIG5vdGlmaWNhdGlvbiBhbmQgcG9wdWxhdGlvbiBkZW5vbWluYXRvciBkYXRhc2V0cyB0b2dldGhlci4KCkhlcmUgd2UgbmVlZCB0byBpbmNsdWRlIHRoZSB3aG9sZSBwb3B1bGF0aW9uICh3aXRoIHNoaXBwaW5nIGFuZCBpbnN0aXR1dGlvbnMpIGFzIHRoZXkgYXJlIGluY2x1ZGVkIGluIHRoZSBub3RpZmljYXRpb25zLgoKYGBge3J9CgpvdmVyYWxsX2luYyA8LSBvdmVyYWxsX3BvcHMgJT4lCiAgbGVmdF9qb2luKGNhc2VzX2J5X3llYXIpCgpvdmVyYWxsX2luYyA8LSBvdmVyYWxsX2luYyAlPiUKICBtdXRhdGUoaW5jX3B1bG1fMTAwayA9IHB1bG1vbmFyeV9ub3RpZmljYXRpb25zL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwLAogICAgICAgICBpbmNfZXBfMTAwayA9IGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwLAogICAgICAgICBpbmNfMTAwayA9IHRvdGFsX25vdGlmaWNhdGlvbnMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApCgpvdmVyYWxsX2luYyAlPiUKICBzZWxlY3QoeWVhciwgaW5jXzEwMGssIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCmBgYHtyfQoKb3ZlcmFsbF9pbmMgJT4lCiAgc2VsZWN0KHllYXIyLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwaykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGluY19wdWxtXzEwMGssIGBpbmNfZXBfMTAwa2ApKSAlPiUKICBtdXRhdGUobmFtZSA9IGNhc2Vfd2hlbihuYW1lID09ICJpbmNfcHVsbV8xMDBrIiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImluY19lcF8xMDBrIiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT12YWx1ZSwgeD15ZWFyMiwgZ3JvdXAgPSBuYW1lLCBmaWxsPW5hbWUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKCmBgYAoKIyMjIyA1LjIgVEIgaW5jaWRlbmNlIGJ5IERpdmlzaW9uCgpgYGB7cn0KCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV9kaXZpc2lvbikKCgpkaXZpc2lvbl9pbmMgPC0gZGl2aXNpb25faW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKZGl2aXNpb25faW5jICU+JQogIHNlbGVjdCh5ZWFyLCBkaXZpc2lvbiwgdGJfdHlwZSwgaW5jXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKYGBge3J9CgpkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBpbmNpZGVuY2UgYnkgV2FyZAoKSGVyZSB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIGluc3RpdHV0aW9ucyBhbmQgaGFyYm91ciBmcm9tIHRoZSBkZW5vbWluYXRvcnMsIGFzIHdlIGRvbid0IGhhdmUgcmVsaWFibGUgcG9wdWxhdGlvbiBkZW5vbWluYXRvcnMgZm9yIHRoZW0uCgpgYGB7cn0KCndhcmRfaW5jIDwtIHdhcmRfcG9wcyAlPiUKICBsZWZ0X2pvaW4oY2FzZXNfYnlfd2FyZCkKCgp3YXJkX2luYyA8LSB3YXJkX2luYyAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSBjYXNlcy9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkKCndhcmRfaW5jICU+JQogIHNlbGVjdCh5ZWFyLCB3YXJkLCB0Yl90eXBlLCBpbmNfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgoKYGBge3J9Cgp3YXJkX2luYyAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9aW5jXzEwMGssIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKHdhcmR+LikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUsIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkluY2lkZW5jZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKCgpgYGAKCk9uIGEgbWFwCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KCnN0X2FzX3NmKGxlZnRfam9pbih3YXJkX2luYywgZ2xhc2dvd193YXJkc18xOTUxKSkgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1pbmNfMTAwaykpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbCA9IDcpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lPSJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJBIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgyLCAiY20iKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIikpCgoKCmBgYAoKCiMjIyA2LiBUQiBNb3J0YWxpdHkKCiMjIyMgNi4xIE92ZXJhbGwgTW9ydGFsaXR5CgpJbXBvcnQgdGhlIFRCIG1vcnRhbGl0eSBkYXRhLgoKRmlyc3QsIG92ZXJhbGwgZGVhdGhzLiBOb3RlIHRoYXQgaW4gdGhlIG9yaWdpbmFsIHJlcG9ydHMsIHdlIGhhdmUgYSBwdWxtb25hcnkgVEIgZGVhdGggcmF0ZSBwZXIgbWlsbGlvbiBmb3IgYWxsIHllYXJzLCBhbmQgbnVtYmVycyBvZiBwdWxtb25hcnkgVEIgZGVhdGhzIGZvciBlYWNoIHllYXIgYXBhcnQgZnJvbSAxOTUwLgoKYGBge3J9CgojZ2V0IHRoZSBvdmVyYWxsIG1vcnRhbGl0eSBzaGVldHMKZGVhdGhzX3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiZGVhdGhzIiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCm92ZXJhbGxfZGVhdGhzIDwtIG1hcF9kZihkZWF0aHNfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKb3ZlcmFsbF9kZWF0aHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCgpgYGAKClBsb3QgdGhlIHJhdyBudW1iZXJzIG9mIHB1bG1vbmFyeSBkZWF0aHMKCmBgYHtyfQoKb3ZlcmFsbF9kZWF0aHMgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cHVsbW9uYXJ5X2RlYXRocykpICsKICBnZW9tX2xpbmUoY29sb3VyID0gIiNERTBEOTIiKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgbGFicyh5PSJQdWxtb25hcnkgVEIgZGVhdGhzIHBlciB5ZWFyIiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB0aXRsZSA9ICJOdW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMiLAogICAgICAgc3VidGl0bGUgPSAiR2xhc2dvdywgMTk1MC0xOTYzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IG5vIGRhdGEgZm9yIDE5NTAiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgpOb3cgdGhlIGluY2lkZW5jZSBvZiBwdWxtb25hcnkgVEIgZGVhdGgKCmBgYHtyfQpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICsKICBnZW9tX2xpbmUoY29sb3VyID0gIiM0RDZDRkEiKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKHk9IkFubnVhbCBpbmNpZGVuY2Ugb2YgZGVhdGggKHBlciAxMDAsMDAwKSIsCiAgICAgICB4ID0gIlllYXIiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M3LnBuZyIpLCB3aWR0aD0xMCkKCmBgYAoKCiMjIyA2LiBUYWJsZSAxCgpNYWtlIFRhYmxlIDEgaGVyZSwgYW5kIHNhdmUgZm9yIHB1YmxpY2F0aW9uLgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lIAogIHNlbGVjdCh5ZWFyLCB0b3RhbF9wb3B1bGF0aW9uKSAlPiUKICBsZWZ0X2pvaW4ob3ZlcmFsbF9pbmMgJT4lCiAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfbm90aWZpY2F0aW9ucywgaW5jX3B1bG1fMTAwaywKICAgICAgICAgICAgICAgICAgICAgYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2AsIGluY19lcF8xMDBrLAogICAgICAgICAgICAgICAgICAgICB0b3RhbF9ub3RpZmljYXRpb25zLCBpbmNfMTAwaykpICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2RlYXRocyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwKICAgICAgICAgICAgICAgICAgICAgcHVsbW9uYXJ5X2RlYXRocywgcHVsbW9uYXJ5X2RlYXRoX3JhdGVfcGVyXzEwMGspKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5yb3VuZCguLCBkaWdpdHM9MSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpIAoKYGBgCgoKCgojIyMgNy4gT3ZlcmFsbCBwdWxtb25hcnkgVEIgbW9kZWwKCgojIyMjIDcuMSBGSXQgdGhlIG1vZGVsIGFuZCBwcmlvcnMKCkZpcnN0IG1vZGVsIHdpbGwgaW52ZXN0aWdhdGUgdGhlIGltcGFjdCBvZiBtYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBvbiBwdWxtb25hcnkgVEIgY2FzZSBub3RpZmljYXRpb24gcmF0ZSB1c2luZyBhbiBpbnRlcnJ1cHRlZCB0aW1lIHNlcmllcyBhbmFseXNpcy4KClNldCB1cCB0aGUgZGF0YQoKYGBge3J9CgptZGF0YTEgPC0gb3ZlcmFsbF9pbmMgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgbXV0YXRlKHlfbnVtID0gMTpucm93KC4pKSAlPiUKICByZW5hbWUoZXh0cmFwdWxtb25hcnlfbm90aWZpY2F0aW9ucyA9IGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgKQoKYGBgCgoKV29yayBvbiB0aGUgcHJpb3JzIGEgYml0CgpCYXNpYyBwcmlvcgoKYGBge3J9CgpiYXNpY19wcmlvciA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjI1KSwgY2xhc3MgPSBiKSkKYGBgCgpMb29rIGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiBjb3VudHMgKGNvdW50cyBvZiBwdWxtb25hcnkgbm90aWZpY2F0aW9ucyBhcmUgd2hhdCB3ZSBhcmUgcHJlZGljdGluZykKCmBgYHtyfQoKI01lYW4gb2YgY291bnRzIHBlciB5ZWFyCm1lYW4obWRhdGExJHB1bG1vbmFyeV9ub3RpZmljYXRpb25zKQojdmFyaWFuY2Ugb2YgY291bnRzIHBlciB5ZWFyCnZhcihtZGF0YTEkcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpCgpgYGAKCgpRdWl0ZSBhIGJpdCBvZiBvdmVyLWRpc3BlcnNpb24gaGVyZSwgc28gbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uIG1pZ2h0IGJlIGEgYmV0dGVyIGNob2ljZSBvZiBkaXN0cmlidXRpb25hbCBmYW1pbHkgdGhhbiBQb2lzc29uLgoKU2xpZ2h0bHkgbW9yZSBpbmZvcm1hdGl2ZSBwcmlvciAoIndlYWtseSBpbmZvcm1hdGl2ZSIgcmVhbGx5KQoKYGBge3J9CgpnZ3Bsb3QoZGF0YSA9IHRpYmJsZSh4ID0gc2VxKGZyb20gPSA1MDAsIHRvID0gNTAwMCwgYnkgPSAxMCkpLAogICAgICAgYWVzKHggPSB4LCB5ID0gZGdhbW1hKHgsIHNoYXBlID0gMC4xLCByYXRlID0gMC4wMDAwMSkpKSArCiAgZ2VvbV9hcmVhKGNvbG9yID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgIGZpbGwgPSAiI0RFMEQ5MiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoTlVMTCkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYyg1MDAsIDUwMDApKSArCiAgZ2d0aXRsZShleHByZXNzaW9uKGJybXN+fmdhbW1hKDAuMSoiLCAiKjAuMDAwMDEpfnNoYXBlfnByaW9yKSkKCgpgYGAKCkZpdCBhIG1vZGVsIHdpdGggb25seSBwcmlvcnMKCmBgYHtyfQoKd2luZm9ybV9wcmlvciA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjEsIDAuMDAwMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMjUpLCBjbGFzcyA9IGIpKQoKCm1fcHVsbW9uYXJ5X3ByaW9yIDwtIGJybSgKICBwdWxtb25hcnlfbm90aWZpY2F0aW9ucyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAgb2Zmc2V0KGxvZyh0b3RhbF9wb3B1bGF0aW9uKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTEsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IsCiAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICAgICAgICAgICAgICAgICAgYmFja2VuZD0iY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpzdW1tYXJ5KG1fcHVsbW9uYXJ5X3ByaW9yKQpjb25kaXRpb25hbF9lZmZlY3RzKG1fcHVsbW9uYXJ5X3ByaW9yKQoKYGBgCgpOb3cgZml0IHRoZSBtb2RlbCB3aXRoIHRoZSB3ZWFrbHkgaW5mb3JtYXRpdmUgcHJpb3JzCgoKYGBge3J9Cm1fcHVsbW9uYXJ5X292ZXJhbGwgPC0gYnJtKAogIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICBvZmZzZXQobG9nKHRvdGFsX3BvcHVsYXRpb24pKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvciwKICAgICAgICAgICAgICAgICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIiwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCnN1bW1hcnkobV9wdWxtb25hcnlfb3ZlcmFsbCkKcGxvdChtX3B1bG1vbmFyeV9vdmVyYWxsKQpwcF9jaGVjayhtX3B1bG1vbmFyeV9vdmVyYWxsLCB0eXBlPSdlY2RmX292ZXJsYXknKQoKYGBgCgojIyMjIDcuMiBTdW1tYXJpc2UgY2hhbmdlIGluIENOUnMKClN1bW1hcmlzZSB0aGUgcG9zdGVyaW9yCgpgYGB7cn0KCmYxYiA8LSBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsID0gbV9wdWxtb25hcnlfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHRvdGFsX3BvcHVsYXRpb24sIG91dGNvbWUgPSBpbmNfcHVsbV8xMDBrLCBncm91cGluZ192YXI9TlVMTCkKICAKZjFiCmBgYAoKTWFrZSB0aGlzIGludG8gYSBmaWd1cmUKCmBgYHtyfQoKZjFhIDwtIHN0X2FzX3NmKGxlZnRfam9pbih3YXJkX2luYywgZ2xhc2dvd193YXJkc18xOTUxKSkgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1pbmNfMTAwaykpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbCA9IDcpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lPSJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJBIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICNsZWdlbmQua2V5LndpZHRoID0gdW5pdCgyLCAiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjUpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCihmMWEgLyBmMWIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMS5wbmciKSkKCmBgYAoKClN1bW1hcnkgb2YgY2hhbmdlIGluIG5vdGlmaWNhdGlvbnMKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhMSwgbW9kZWw9bV9wdWxtb25hcnlfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj10b3RhbF9wb3B1bGF0aW9uLCBncm91cGluZ192YXI9TlVMTCkgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCmBgYAooQWx0ZXJuYXRpdmUgd2F5IC0ga2VlcCBpbiBmb3Igbm93KQoKYGBge3J9CgpvdmVyYWxsX2ltbWVkaWF0ZV9kcmF3cyA8LSBtZGF0YTEgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgdG90YWxfcG9wdWxhdGlvbiwgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTcpKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9wdWxtb25hcnlfb3ZlcmFsbCkgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKSAlPiUKICBncm91cF9ieSguZHJhdykgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfaW1tZWRpYXRlID0gKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIHVuZ3JvdXAoKQoKb3ZlcmFsbF9wb3N0X2RyYXdzIDwtIG1kYXRhMSAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCB0b3RhbF9wb3B1bGF0aW9uLCBwdWxtb25hcnlfbm90aWZpY2F0aW9ucykgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV9vdmVyYWxsKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApICU+JQogIGdyb3VwX2J5KC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9wb3N0ID0gKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIHVuZ3JvdXAoKQoKCm92ZXJhbGxfc2xvcGVfZHJhd3MgPC0gbWRhdGExICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHRvdGFsX3BvcHVsYXRpb24sIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1MCwgMTk1NiwgMTk1OCwgMTk2MykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV9vdmVyYWxsKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWFjZl9wZXJpb2QpICU+JQogIGdyb3VwX2J5KGFjZl9wZXJpb2QsIC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9zbG9wZSA9ICgobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkvbl95ZWFycykgJT4lCiAgZGlzdGluY3QoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYyhhY2ZfcGVyaW9kKSwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHBjdF9jaGFuZ2Vfc2xvcGUpICU+JQogIG11dGF0ZShyYXRpb19hbm51YWxfc2xvcGUgPSBgYy4gcG9zdC1hY2ZgIC8gYGEuIHByZS1hY2ZgKQoKCmBgYAoKQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgZWZmZWN0IGFuZCBwb3N0IGVmZmVjdCBvZiBBQ0YKCmBgYHtyfQoKbGVmdF9qb2luKG92ZXJhbGxfaW1tZWRpYXRlX2RyYXdzLCBvdmVyYWxsX3Bvc3RfZHJhd3MpICU+JQogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1wY3RfY2hhbmdlX3Bvc3QpKSArCiAgZ2VvbV9oZHIoCiAgICBhZXMoZmlsbCA9IGFmdGVyX3N0YXQocHJvYnMpKSwgCiAgICBhbHBoYSA9IDEpICsKICAjZ2VvbV9oZHJfcG9pbnRzKGFlcyhjb2xvdXIgPSBhZnRlcl9zdGF0KHByb2JzKSksIHNpemU9MC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLjI1LCBsYWJlbC55ID0gLTAuMjUsIHNpemU9NCkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNSkpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb249IkUiLCBuYW1lPSIiKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIiwKICAgICAgIGNhcHRpb249IkJvdW5kYXJpZXMgYXJlIHBvc3RlcmlvciBkZXNuaXR5IGludGVydmFscyBmcm9tIDQwMDAgZHJhd3MiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgpDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBlZmZlY3QgYW5kIGNoYW5nZSBpbiBzbG9wZQoKYGBge3J9CgpsZWZ0X2pvaW4ob3ZlcmFsbF9pbW1lZGlhdGVfZHJhd3MsIG92ZXJhbGxfc2xvcGVfZHJhd3MpICU+JQogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1yYXRpb19hbm51YWxfc2xvcGUpKSArCiAgZ2VvbV9oZHIoCiAgICBhZXMoZmlsbCA9IGFmdGVyX3N0YXQocHJvYnMpKSwgCiAgICBhbHBoYSA9IDEpICsKICAjZ2VvbV9oZHJfcG9pbnRzKGFlcyhjb2xvdXIgPSBhZnRlcl9zdGF0KHByb2JzKSksIHNpemU9MC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgI3N0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMC4yNSwgbGFiZWwueSA9IDAuMDIsIHNpemU9NCkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgMTApKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uPSJFIiwgbmFtZT0iIikgKwogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIEFDRiBpbXBhY3QgYW5kIHBvc3QtQUNGIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgICAgeT0iUG9zdCBpbnRlcnZlbnRpb24gaW1wYWN0OiBQZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBkcmF3cyBmcm9tIHBvc3RlaW9yIGRpc3RyaWJ1dGlvbiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCgoKCiMjIyMgNy4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmIDwtIGNhbGN1YXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fcHVsbW9uYXJ5X292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uKQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpUb3RhbCBwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKCgojIyMgOC4gRXh0cmEtcHVsbW9uYXJ5IFRCIG5vdGlmaWNhdGlvbnMKCiMjIyMgOC4xIEZpdCB0aGUgbW9kZWwKCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9RkFMU0V9CgptX2V4dHJhcF9vdmVyYWxsIDwtIGJybSgKICBleHRyYXB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArIG9mZnNldChsb2codG90YWxfcG9wdWxhdGlvbikpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGExLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IGJhc2ljX3ByaW9yLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKc3VtbWFyeShtX2V4dHJhcF9vdmVyYWxsKQpwbG90KG1fZXh0cmFwX292ZXJhbGwpCnBwX2NoZWNrKG1fZXh0cmFwX292ZXJhbGwsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKCgpgYGB7cn0KcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGExLCBtb2RlbD1tX2V4dHJhcF9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbiwgb3V0Y29tZT1pbmNfZXBfMTAwaykKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczYucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIyA4LjIgU3VtbWFyeSBvZiBjaGFuZ2UKCkEuIFBlcmNlbnRhZ2UgY2hhbmdlIGluIG1vcnRhbGl0eSwgZnJvbSAxOTU2IHRvIDE5NTcgKGkuZS4gaW1tZWRpYXRlIEFDRiBlZmZlY3QpCgpgYGB7cn0KCnN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YT1tZGF0YTEsIG1vZGVsID0gbV9leHRyYXBfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHRvdGFsX3BvcHVsYXRpb24pICU+JQogIG1hcChkYXRhdGFibGUpCgpgYGAKCgoKIyMjIyA4LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKb3ZlcmFsbF9lcF9jb3VudGVyZiA8LSBjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGExLCBtb2RlbD1tX2V4dHJhcF9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbikKCm92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKClRvdGFsIGV4dHJhIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgojIyMgOS4gV2FyZCBsZXZlbCBtb2RlbAoKIyMjIyA5LjEgRml0IHRoZSBtb2RlbAoKYGBge3J9CgptZGF0YTIgPC0gd2FyZF9pbmMgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKCgpgYGAKCihOb3RlIHRoZSBkZW5vbWluYXRvciB3aXRob3V0IGluc3RpdHV0aW9uYWxpc2VkIHBlb3BsZSBhbmQgInNoaXBwaW5nIiEpCgpgYGB7cn0KI3dlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMgZm9yIG11bHRpbGV2ZWwgbW9kZWwKYmFzaWNfcHJpb3IyIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMSksIGNsYXNzID0gYiksCiAgICAgICAgICAgICAgICAgcHJpb3IoY2F1Y2h5KDAsNSksIGNsYXNzPSJzZCIpKQoKCmdncGxvdChkYXRhID0gdGliYmxlKHggPSBzZXEoZnJvbSA9IDAsIHRvID0gMjUwLCBieSA9IDEwKSksCiAgICAgICBhZXMoeCA9IHgsIHkgPSBkZ2FtbWEoeCwgc2hhcGUgPSAwLjUsIHJhdGUgPSAwLjAxKSkpICsKICBnZW9tX2FyZWEoY29sb3IgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgZmlsbCA9ICIjREUwRDkyIikgKwogIHNjYWxlX3hfY29udGludW91cyhOVUxMKSArCiAgc2NhbGVfeV9jb250aW51b3VzKE5VTEwsIGJyZWFrcyA9IE5VTEwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMjUwKSkgKwogIGdndGl0bGUoZXhwcmVzc2lvbihicm1zfn5nYW1tYSgwLjUqIiwgIiowLjAwMDAxKX5zaGFwZX5wcmlvcikpCgp3aW5mb3JtX3ByaW9yMiA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjUsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpLAogICAgICAgICAgICAgICAgICBwcmlvcihjYXVjaHkoMCw1KSwgY2xhc3M9InNkIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9ImNvciIpKQpgYGAKCgpgYGB7cn0KCm1fcHVsbW9uYXJ5X3dhcmRfcHJpb3IgPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICgxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTIsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IyLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpjb25kaXRpb25hbF9lZmZlY3RzKG1fcHVsbW9uYXJ5X3dhcmRfcHJpb3IpCgoKYGBgCgpOb3cgZml0IHRoZSBtb2RlbCB3aXRoIGRhdGEKCmBgYHtyfQptX3B1bG1vbmFyeV93YXJkIDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAoMSArIHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gfCB3YXJkKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEyLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yMiwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIpCgpzdW1tYXJ5KG1fcHVsbW9uYXJ5X3dhcmQpCnBsb3QobV9wdWxtb25hcnlfd2FyZCkKcHBfY2hlY2sobV9wdWxtb25hcnlfd2FyZCwgdHlwZT0nZWNkZl9vdmVybGF5JykKCgpgYGAKCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMiwgbW9kZWw9bV9wdWxtb25hcnlfd2FyZCwgb3V0Y29tZSA9IGluY18xMDBrLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCkKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczQucG5nIiksIHdpZHRoPTEwLCBoZWlnaHQ9MTIpCgpgYGAKCiMjIyMgOS4yIFN1bW1hcnkgb2YgY2hhbmdlCgpBLiBwZXJjZW50YWdlIGluY3JlYXNlIGluIENOUiwgZnJvbSAxOTU2IHRvIDE5NTcgKGkuZS4gaW1tZWRpYXRlIEFDRiBlZmZlY3QpCgpgYGB7cn0KCndhcmRfY2hhbmdlIDwtIHN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YSA9IG1kYXRhMiwgbW9kZWwgPSBtX3B1bG1vbmFyeV93YXJkLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPXdhcmQpIAoKd2FyZF9jaGFuZ2UgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCmBgYAoKQXMgYSBzdXBwbGVtZW50YXJ5IGZpZ3VyZQoKYGBge3J9CiAgCndhcmRfY2hhbmdlJGltbWVkaWF0ZV9jaGFuZ2UgJT4lCiAgYXJyYW5nZShhY2ZfaW5jMTAwa19ycikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1hY2ZfaW5jMTAwa19yciwgeW1pbj1hY2ZfaW5jMTAwa19yci5sb3dlciwgeW1heD1hY2ZfaW5jMTAwa19yci51cHBlciwgCiAgICAgICAgICAgICAgICAgICAgICB4PWZjdF9yZW9yZGVyKHdhcmQsIGFjZl9pbmMxMDBrX3JyKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFjZl9pbmMxMDBrX3JyKSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Iob3B0aW9uID0gIkQiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC44LDMuMCkpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBwb3N0ZXJpb3IgcHJlZGljdGVkIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwOyA5NSUgVUkpXG5BQ0YgKDE5NTcpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M1LnBuZyIpKQoKYGBgCgoKYGBge3J9Cgp3YXJkX2NoYW5nZSRwb3N0X2NoYW5nZSAlPiUKICBhcnJhbmdlKGFjZl9pbmMxMDBrX3JyKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9pbmMxMDBrX3JyLCB5bWluPWFjZl9pbmMxMDBrX3JyLmxvd2VyLCB5bWF4PWFjZl9pbmMxMDBrX3JyLnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9ZmN0X3Jlb3JkZXIod2FyZCwgYWNmX2luYzEwMGtfcnIpLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWNmX2luYzEwMGtfcnIpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYihvcHRpb24gPSAiRCIpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC44LDMuMCkpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBwb3N0ZXJpb3IgcHJlZGljdGVkIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwOyA5NSUgVUkpXG5BZnRlciBBQ0YgKDE5NTgpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNi5wbmciKSkKCgpgYGAKCgpwZXJjZW50YWdlIGNoYW5nZSA9IChmaW5hbCB2YWx1ZSAtIGluaXRpYWwgdmFsdWUpIC8gaW5pdGlhbCB2YWx1ZQoKYGBge3J9Cgp3YXJkX2NoYW5nZSRzbG9wZV9jaGFuZ2UgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1wY3RfY2hhbmdlX2VwcmVkX292ZXJhbGwgLCB5bWluPXBjdF9jaGFuZ2VfbG93ZXJfb3ZlcmFsbCAsIHltYXg9cGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsICwKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwPWFjZl9wZXJpb2QsIGNvbG91cj1hY2ZfcGVyaW9kLAogICAgICAgICAgICAgICAgICAgICAgeCA9IGZjdF9yZW9yZGVyKHdhcmQsIHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCApKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9cGVyY2VudCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICIjNEQ2Q0ZBIikpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC44LDMuMCkpICsKICBsYWJzKHRpdGxlPSJJbnRlcnZlbnRpb24gZWZmZWN0IG9mIG1hc3MgbWluaWF0dXJlIGNoZXN0IFgtcmF5IGluIEdsYXNnb3ciLAogICAgICAgc3VidGl0bGU9IkJ5IG11bmljaXBhbCB3YXJkIiwKICAgICAgIHg9IiIsCiAgICAgICB5PSJNZWFuIGFubnVhbCByYXRlIG9mIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICg5NSUgQ3JJKVxuIEJlZm9yZSBBQ0YgKDE5NTAtMTk1NikgdnMuIGFmdGVyIEFDRiAoMTk1OC0xOTYzKSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCmBgYAoKKEFsdGVybmF0aXZlIGZpZ3VyZSAtIGtlZXAgaW4gZm9yIHRoZSBtaW51dGUpCgpJcyB0aGVyZSBhbnkgY29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgaW5jcmVhc2UgYW5kIGEpIHBvc3QtaW50ZXJ2ZW50aW9uICgxOTU4KSBlZmZlY3QsIGFuZCBiKSBwb3N0IGludGVydmVudGlvbiBzbG9wZSAoMTk1OC0xOTYzKQoKYGBge3J9Cgp3YXJkX2NvcnMgPC0gd2FyZF9pbXBhY3Rfb3V0ICU+JQogIHNlbGVjdCh3YXJkLCBpbW1lZGlhdGVfZWZmZWN0ID0gYWNmX2luYzEwMGtfcnIsCiAgICAgICAgICAgICAgIGltbWVkaWF0ZV9lZmZlY3RfbG93ZXIgPSBhY2ZfaW5jMTAwa19yci5sb3dlciwKICAgICAgICAgICAgICAgaW1tZWRpYXRlX2VmZmVjdF91cHBlciA9IGFjZl9pbmMxMDBrX3JyLnVwcGVyKSAlPiUKICByaWdodF9qb2luKAogICAgd2FyZF9wdWxtX2ltcGFjdDIgJT4lIAogICAgICBzZWxlY3Qod2FyZCwgcG9zdF9lZmZlY3QgPSBhY2ZfaW5jMTAwa19yciwKICAgICAgICAgICAgICAgcG9zdF9lZmZlY3RfbG93ZXIgPSBhY2ZfaW5jMTAwa19yci5sb3dlciwKICAgICAgICAgICAgICAgcG9zdF9lZmZlY3RfdXBwZXIgPSBhY2ZfaW5jMTAwa19yci51cHBlcikKICApICU+JQogIHJpZ2h0X2pvaW4oCiAgICB3YXJkX3B1bG1faW1wYWN0MyAlPiUKICAgICAgZmlsdGVyKGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIpICU+JQogICAgICBzZWxlY3Qod2FyZCwgc2xvcGVfZWZmZWN0ID0gcGN0X2NoYW5nZV9lcHJlZF9hbm51YWwsCiAgICAgICAgICAgICBzbG9wZV9lZmZlY3RfbG93ZXIgPSBwY3RfY2hhbmdlX2xvd2VyX2FubnVhbCwKICAgICAgICAgICAgIHNsb3BlX2VmZmVjdF91cHBlciA9IHBjdF9jaGFuZ2VfdXBwZXJfYW5udWFsKQogICkKCndhcmRfY29ycyAlPiUKICBnZ3Bsb3QoYWVzKHg9aW1tZWRpYXRlX2VmZmVjdCwgeG1pbj1pbW1lZGlhdGVfZWZmZWN0X2xvd2VyLCB4bWF4PWltbWVkaWF0ZV9lZmZlY3RfdXBwZXIsCiAgICAgICAgICAgICB5PXBvc3RfZWZmZWN0LCB5bWluPXBvc3RfZWZmZWN0X2xvd2VyLCB5bWF4PXBvc3RfZWZmZWN0X3VwcGVyLAogICAgICAgICAgICAgZ3JvdXAgPSB3YXJkKSkgKwogIGdlb21fZXJyb3JiYXIoKSArCiAgZ2VvbV9lcnJvcmJhcmgoKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIEFDRiBpbXBhY3QgYW5kIHBvc3QtQUNGIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgICAgeT0iUmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoMTk1OCB2cy4gMTk1NilcblBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdCIsCiAgICAgICB4PSJSZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICgxOTU3IHZzLiAxOTU2KVxuSW1tZWRpYXRlIGltcGFjdCIsCiAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIG11bmljaXBhbCB3YXJkcyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCndhcmRfY29ycyAlPiUKICBnZ3Bsb3QoYWVzKHg9aW1tZWRpYXRlX2VmZmVjdCwgeG1pbj1pbW1lZGlhdGVfZWZmZWN0X2xvd2VyLCB4bWF4PWltbWVkaWF0ZV9lZmZlY3RfdXBwZXIsCiAgICAgICAgICAgICB5PXNsb3BlX2VmZmVjdCwgeW1pbj1zbG9wZV9lZmZlY3RfbG93ZXIsIHltYXg9c2xvcGVfZWZmZWN0X3VwcGVyLAogICAgICAgICAgICAgZ3JvdXAgPSB3YXJkKSkgKwogIGdlb21fZXJyb3JiYXIoKSArCiAgZ2VvbV9lcnJvcmJhcmgoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBtZWFuIHJhdGUgb2YgY2hhbmdlIiwKICAgICAgIHk9IlBvc3QgQUNGIG1lYW4gYW5udWFsIHJhdGUgb2YgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIiwKICAgICAgIHg9IlJlbGF0aXZlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDE5NTcgdnMuIDE5NTYpXG5JbW1lZGlhdGUgaW1wYWN0IiwKICAgICAgIGNhcHRpb249IlBvaW50cyBhcmUgbXVuaWNpcGFsIHdhcmRzIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCgpgYGAKClRyeSBhIGRpZmZlcmVudCB3YXkgd2l0aCB0aGUgZnVsbCBkaXN0cmlidXRpb24gb2YgcG9zdGVyaW9ycwoKCmBgYHtyfQoKd2FyZF9pbW1lZGlhdGVfZHJhd3MgPC0gbWRhdGEyICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGNhc2VzLCB3YXJkKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NiwxOTU3KSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X3dhcmQpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiAgZ3JvdXBfYnkod2FyZCwgLmRyYXcpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX2ltbWVkaWF0ZSA9IChsYXN0KGluY18xMDBrKSAtIGZpcnN0KGluY18xMDBrKSkvZmlyc3QoaW5jXzEwMGspKSAlPiUKICBhcnJhbmdlKHdhcmQpICU+JQogIHVuZ3JvdXAoKQoKd2FyZF9wb3N0X2RyYXdzIDwtIG1kYXRhMiAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBjYXNlcywgd2FyZCkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIGdyb3VwX2J5KHdhcmQsIC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9wb3N0ID0gKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIGFycmFuZ2Uod2FyZCkgJT4lCiAgdW5ncm91cCgpCgoKd2FyZF9zbG9wZV9kcmF3cyA8LSBtZGF0YTIgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgY2FzZXMsIHdhcmQpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTUwLCAxOTU2LCAxOTU4LCAxOTYzKSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X3dhcmQpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3llYXJzID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+IDcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+IDYpKSAlPiUKICBncm91cF9ieSh3YXJkLCBhY2ZfcGVyaW9kLCAuZHJhdykgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2Vfc2xvcGUgPSAoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpL25feWVhcnMpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGMoYWNmX3BlcmlvZCksCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBwY3RfY2hhbmdlX3Nsb3BlKSAlPiUKICBtdXRhdGUocmF0aW9fYW5udWFsX3Nsb3BlID0gYGMuIHBvc3QtYWNmYCAvIGBhLiBwcmUtYWNmYCkKICAKCgoKCmBgYAoKCkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGVmZmVjdCBhbmQgcG9zdCBlZmZlY3Qgb2YgQUNGCgpgYGB7cn0KCgpsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3MsIHdhcmRfcG9zdF9kcmF3cykgJT4lCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXBjdF9jaGFuZ2VfcG9zdCwgZ3JvdXA9d2FyZCkpICsKICBnZW9tX2hkcl9wb2ludHMoc2l6ZT0wLjEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDAsIGxhYmVsLnkgPSAwLjI1LCBzaXplPTQpICsKICBzY2FsZV9jb2xvdXJfc2NpY29fZChwYWxldHRlID0gImxpcGFyaSIsIG5hbWUgPSAiUG9zdGVyaW9yIHByb2JhYmlsaXR5IikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKICAgICAgIHk9IlBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdDogZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBkcmF3cyBmcm9tIHBvc3RlaW9yIGRpc3RyaWJ1dGlvbiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKQoKCmBgYAoKQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgZWZmZWN0IGFuZCBjaGFuZ2UgaW4gc2xvcGUKCmBgYHtyfQoKbGVmdF9qb2luKHdhcmRfaW1tZWRpYXRlX2RyYXdzLCB3YXJkX3Nsb3BlX2RyYXdzKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGN0X2NoYW5nZV9pbW1lZGlhdGUsIHk9cmF0aW9fYW5udWFsX3Nsb3BlLCBncm91cD13YXJkKSkgKwogIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvdXI9ImJsYWNrIiwgbGluZXdpZHRoPTAuNSkgKwogICNzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDAsIGxhYmVsLnkgPSAwLjAyLCBzaXplPTQpICsKICBzY2FsZV9jb2xvdXJfc2NpY29fZChwYWxldHRlID0gImxpcGFyaSIsIG5hbWUgPSAiUG9zdGVyaW9yIHByb2JhYmlsaXR5IikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTApKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IFBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1OCB2cy4gMTk1NikiLAogICAgICAgeD0iSW1tZWRpYXRlIGltcGFjdDogcGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU3IHZzLiAxOTU2KSIsCiAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIGRyYXdzIGZyb20gcG9zdGVpb3IgZGlzdHJpYnV0aW9uIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pCgoKYGBgCgoKSm9pbiB0aGVzZSB0b2dldGhlciB3aXRoIHRoZSBvdmVyYWxsIGVzdGltYXRlcyB0byBtYWtlIGEgc2luZ2xlIGZpZ3VyZSBmb3Igc2hvd2luZyBpbXBhY3QKCmBgYHtyfQoKZjJfZGF0YSA8LSAKICBsZWZ0X2pvaW4ob3ZlcmFsbF9pbW1lZGlhdGVfZHJhd3MsIG92ZXJhbGxfcG9zdF9kcmF3cykgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfc2xvcGVfZHJhd3MpICU+JQogIG11dGF0ZShsZXZlbCA9ICJvdmVyYWxsIiwKICAgICAgICAgd2FyZCA9ICJHbGFzZ293IikgJT4lCiAgYmluZF9yb3dzKAogICAgbGVmdF9qb2luKHdhcmRfaW1tZWRpYXRlX2RyYXdzLCB3YXJkX3Bvc3RfZHJhd3MpICU+JQogIGxlZnRfam9pbih3YXJkX3Nsb3BlX2RyYXdzKSAlPiUKICBtdXRhdGUobGV2ZWwgPSAid2FyZCIpCiAgKQoKZjJhIDwtIGYyX2RhdGEgJT4lIAogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1wY3RfY2hhbmdlX3Bvc3QsIGdyb3VwPXdhcmQpKSArCiAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLCBsYWJlbC55ID0gMC4xMiwgc2l6ZT00KSArCiAgc2NhbGVfY29sb3VyX3NjaWNvX2QocGFsZXR0ZSA9ICJsaXBhcmkiLCBuYW1lID0gIlBvc3RlcmlvciBwcm9iYWJpbGl0eSBkZW5zaXR5IikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsKICBsYWJzKHk9IlBvc3QtaW50ZXJ2ZW50aW9uIGltcGFjdDogUGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgZmFjZXRfd3JhcChmY3RfcmVsZXZlbCh3YXJkLAogICAgICAgICAgICAgICAgICAgICAgICAgIkdsYXNnb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgYWZ0ZXI9MCl+LiwgbmNvbCA9IDUpICsgCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQoKZjJhCgpmMmIgPC0gZjJfZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXJhdGlvX2FubnVhbF9zbG9wZSwgZ3JvdXA9d2FyZCkpICsKICBnZW9tX2hkcl9wb2ludHMoc2l6ZT0wLjEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDEuMiwgbGFiZWwueSA9IDEyLCBzaXplPTQpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNCksCiAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsMTUpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uPSJFIikgKwogIGxhYnMoeT0iUG9zdC1pbnRlcnZlbnRpb24gaW1wYWN0OiBSZWxhdGl2ZSBjaGFuZ2UgaW4gYW5udWFsIENOUiBzbG9wZSAoMTk1OC0xOTYzIHZzLiAxOTUwLTE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY29sb3VyPSJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgZGVuc2l0eSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGZhY2V0X3dyYXAoZmN0X3JlbGV2ZWwod2FyZCwKICAgICAgICAgICAgICAgICAgICAgICAgICJHbGFzZ293IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFmdGVyPTApfi4sIG5jb2wgPSA1KSArIAogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKCmYyYgoKKGYyYSAvIGYyYikgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdBJykKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL2YyLnBuZyIpLCBoZWlnaHQ9MTgsIHdpZHRoPTEwKQoKYGBgCgojIyMjIDkuMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKYGBge3J9Cgp3YXJkX2NvdW50ZXJmIDwtIGNhbGN1YXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTIsIG1vZGVsPW1fcHVsbW9uYXJ5X3dhcmQsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9d2FyZCkKCndhcmRfY291bnRlcmYgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCgpgYGAKClRvdGFsIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9Cgp3YXJkX2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZCwgY2FzZXNfYXZlcnRlZC5sb3dlciwgY2FzZXNfYXZlcnRlZC51cHBlciksIHN1bSksIC5ieT13YXJkKQoKCgpgYGAKCiMjIyAxMC4gQWdlLXNleCBtb2RlbAoKIyMjIyAxMC4xIEZJdCB0aGUgbW9kZWwKCkZpdCB0aGUgbW9kZWwKCihOb3QgcmV3cml0dGVuIHRoZSBmdW5jdGlvbnMgZm9yIHRoaXMgeWV0KQoKYGBge3J9CgptZGF0YTMgPC0gY2FzZXNfYnlfYWdlX3NleCAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKHllYXIgJWluJSBjKDE5NTA6MTk1NikgfiAiYS4gcHJlLWFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1NykgfiAiYi4gYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU4OjE5NjMpIH4gImMuIHBvc3QtYWNmIikpICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCndpbmZvcm1fcHJpb3IzIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgICNwcmlvcihnYW1tYSgwLjUsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpLAogICAgICAgICAgICAgICAgICBwcmlvcihjYXVjaHkoMCw1KSwgY2xhc3M9InNkIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9ImNvciIpKQoKCm1fYWdlX3NleCA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIChhY2ZfcGVyaW9kKSooYWdlKnNleCkgKyAoYWNmX3BlcmlvZDp5X251bSkqKGFnZSpzZXgpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEzLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBiYXNpY19wcmlvciwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIpCgpzdW1tYXJ5KG1fYWdlX3NleCkKcGxvdChtX2FnZV9zZXgpCnBwX2NoZWNrKG1fYWdlX3NleCwgdHlwZT0nZWNkZl9vdmVybGF5JykKCgpgYGAKClN1bW1hcmlzZSBwb3N0ZXJpb3IKCmBgYHtyfQoKI3Bvc3RlcmlvciBkcmF3cywgYW5kIHN1bW1hcmlzZQphZ2Vfc2V4X3N1bW1hcnkgPC0gbWRhdGEzICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQoKI2NyZWF0ZSB0aGUgY291bnRlcmZhY3R1YWwgKG5vIGludGVydmVudGlvbiksIGFuZCBzdW1tYXJpc2UKYWdlX3NleF9jb3VudGVyZmFjdCA8LSAKICB0aWJibGUoeWVhciA9IG1kYXRhMyR5ZWFyLAogICAgICAgICB5ZWFyMiA9IG1kYXRhMyR5ZWFyMiwKICAgICAgICAgeV9udW0gPSBtZGF0YTMkeV9udW0sCiAgICAgICAgIGFnZSA9IG1kYXRhMyRhZ2UsCiAgICAgICAgIHNleCA9IG1kYXRhMyRzZXgsCiAgICAgICAgIGFjZl9wZXJpb2QgPSBmYWN0b3IoImEuIHByZS1hY2YiKSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKCkgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSAiTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSAiRiIgfiAiRmVtYWxlIikpIAoKCgphZ2Vfc2V4X3N1bW1hcnkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSAiTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSAiRiIgfiAiRmVtYWxlIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3JpYmJvbihhZXMoeW1pbj0uZXByZWQubG93ZXIsIHltYXg9LmVwcmVkLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogIGdlb21fcmliYm9uKGRhdGEgPSBhZ2Vfc2V4X2NvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgIGFlcyh5bWluPS5lcHJlZC5sb3dlciwgeW1heD0uZXByZWQudXBwZXIsIHg9eWVhcjIsIGZpbGw9IkNvdW50ZXJmYWN0dWFsIiksIGFscGhhPTAuNSkgKwogIGdlb21fbGluZShkYXRhID0gYWdlX3NleF9jb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeT0uZXByZWQsIHg9eWVhcjIsIGNvbG91cj0iQ291bnRlcmZhY3R1YWwiKSkgKwogIGdlb21fbGluZShhZXMoeT0uZXByZWQsIHg9eWVhcjIsIGdyb3VwPWFjZl9wZXJpb2QsICBjb2xvdXI9YWNmX3BlcmlvZCkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtZGF0YTMgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSAiTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSAiRiIgfiAiRmVtYWxlIikpICwgYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIHNoYXBlPWFjZl9wZXJpb2QpLCBzaXplPTIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgZ2doNHg6OmZhY2V0X2dyaWQyKGFnZX5zZXgsIHNjYWxlcyA9ICJmcmVlX3kiLCBpbmRlcGVuZGVudCA9ICJ5IikgKwogIHRoZW1lX2dnZGlzdCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIikgKwogIHNjYWxlX3NoYXBlX2Rpc2NyZXRlKG5hbWU9IiIpICsKICBsYWJzKAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb25zIChuKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKSArCiAgZ3VpZGVzKHNoYXBlPSJub25lIikKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIGhlaWdodD0xMCkKCmBgYAoKIyMjIyAxMC4yIFN1bW1hcnkgb2YgaW1wYWN0IG9mIGludGVydmVudGlvbgoKMS4gcGVyY2VudGFnZSBpbmNyZWFzZSBpbiBDTlIsIGZyb20gMTk1NiB0byAxOTU3IChpLmUuIGltbWVkaWF0ZSBBQ0YgZWZmZWN0KQoKYGBge3J9CgpuZCA8LSBtZGF0YTMgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTY6MTk1NykpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCB5X251bSwgYWdlLCBzZXgpCgoKYWdlX3NleF9pbXBhY3Rfb3V0IDwtIAogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICBuZXdkYXRhPW5kKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIC5lcHJlZCwgYWdlLCBzZXgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhY2ZfcGVyaW9kLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gLmVwcmVkLAogICAgICAgICAgICAgIHZhbHVlc19mbiA9IGxpc3QpICU+JQogIHVubmVzdCgpICU+JQogIHJlbmFtZShwcmVfZXByZWQgPSAzLAogICAgICAgICBwb3N0X2VwcmVkID0gNCkgJT4lCiAgbXV0YXRlKGFjZl9kaWZmID0gcG9zdF9lcHJlZC1wcmVfZXByZWQsCiAgICAgICAgIGFjZl9yciA9IHBvc3RfZXByZWQvcHJlX2VwcmVkKSAlPiUKICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaShhY2ZfZGlmZiwgYWNmX3JyKSAKCmFnZV9zZXhfaW1wYWN0X291dCAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCB+IHNjYWxlczo6bnVtYmVyKHggPSAuLCBhY2N1cmFjeSA9IDAuMDEsIGJpZy5tYXJrID0gIiwiKSkgJT4lCiAgZGF0YXRhYmxlKCkKICAKZjNhIDwtIGFnZV9zZXhfaW1wYWN0X291dCAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1hY2ZfcnIsIHltaW49YWNmX3JyLmxvd2VyLCB5bWF4PWFjZl9yci51cHBlciwgZ3JvdXA9c2V4LCAKICAgICAgICAgICAgICAgICAgICAgIHg9YWdlLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2V4KSwKICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMjUpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygicHVycGxlIiwgImRhcmtvcmFuZ2UiKSwgbmFtZT0iIikgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIG5vdGlmaWNhdGlvbnMgKDk1JSBVSSlcbkFDRiAoMTk1NykgdnMuIEJlZm9yZSBBQ0YgKDE5NTYpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQogIAogIAoKYGBgCgoKMi4gQ2hhbmdlIGZyb20gcHJlLUFDRiBwZXJpb2QgKDE5NTYpLCB0byBmaXJzdCB5ZWFyIHBvc3QtQUNGICgxOTU4KQoKCmBgYHtyfQoKbmQgPC0gbWRhdGEzICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTgpKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgeV9udW0sIGFnZSwgc2V4KQoKI0RvIGl0IHdpdGggY2FsY3VsYXRpbmcgaW5jaWRlbmNlLCB0aGVuIHN1bWFtcmlzaW5nLgphZ2Vfc2V4X2ltcGFjdDIgPC1hZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgbmV3ZGF0YT1uZCkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCAuZXByZWQsIGFnZSwgc2V4KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYWNmX3BlcmlvZCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IC5lcHJlZCwKICAgICAgICAgICAgICB2YWx1ZXNfZm4gPSBsaXN0KSAlPiUKICB1bm5lc3QoKSAlPiUKICByZW5hbWUocHJlX2VwcmVkID0gMywKICAgICAgICBwb3N0X2VwcmVkID0gNCkgJT4lCiAgbXV0YXRlKGFjZl9kaWZmID0gcG9zdF9lcHJlZC1wcmVfZXByZWQsCiAgICAgICAgIGFjZl9yciA9IHBvc3RfZXByZWQvcHJlX2VwcmVkKSAlPiUKICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaShhY2ZfZGlmZiwgYWNmX3JyKSAKCmFnZV9zZXhfaW1wYWN0MiAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCB+IHNjYWxlczo6bnVtYmVyKHggPSAuLCBhY2N1cmFjeSA9IDAuMDEsIGJpZy5tYXJrID0gIiwiKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmYzYiA8LSBhZ2Vfc2V4X2ltcGFjdDIgJT4lICAKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1hY2ZfcnIsIHltaW49YWNmX3JyLmxvd2VyLCB5bWF4PWFjZl9yci51cHBlciwgZ3JvdXA9c2V4LCAKICAgICAgICAgICAgICAgICAgICAgIHg9YWdlLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2V4KSwKICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMjUpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygicHVycGxlIiwgImRhcmtvcmFuZ2UiKSwgbmFtZT0iIikgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIG5vdGlmaWNhdGlvbnMgKDk1JSBVSSlcbkFDRiAoMTk1OCkgdnMuIEJlZm9yZSBBQ0YgKDE5NTYpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCmBgYAoKMy4gQ2hhbmdlIGluIHNsb3BlIChpLmUuIGRpZmZlcmVuY2UgaW4gbWVhbiBhbm51YWwgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBwcmUtSW50ZXJ2ZW50aW9uIHZzLiBwb3N0LWludGVydmVudGlvbiwgYnkgd2FyZCkKCmBgYHtyfQoKYWdlX3NleF9pbXBhY3QzIDwtIG1kYXRhMyAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBjYXNlcywgYWdlLCBzZXgpICU+JQogIGZpbHRlcih5ZWFyIT0xOTU3KSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCwgYWNmX3BlcmlvZCkgJT4lCiAgbWVhbl9xaSguZXByZWQpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWFjZl9wZXJpb2QpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX2VwcmVkX292ZXJhbGwgPSAoKChsYXN0KC5lcHJlZCkgLSBmaXJzdCguZXByZWQpKS9maXJzdCguZXByZWQpKSksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfb3ZlcmFsbCA9ICgoKGxhc3QoLmxvd2VyKSAtIGZpcnN0KC5sb3dlcikpL2ZpcnN0KC5sb3dlcikpKSwKICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkpLAogICAgCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfZXByZWRfYW5udWFsID0gKCgobGFzdCguZXByZWQpIC0gZmlyc3QoLmVwcmVkKSkvZmlyc3QoLmVwcmVkKSkvbl95ZWFycyksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkvbl95ZWFycyksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfdXBwZXJfYW5udWFsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkvbl95ZWFycyksCiAgICAgICAgICAgIC5ieSA9IGMoYWNmX3BlcmlvZCwgYWdlLCBzZXgpKSAlPiUKICBkaXN0aW5jdCgpCgoKYWdlX3NleF9pbXBhY3QzICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIHBlcmNlbnQpICU+JQogIGRhdGF0YWJsZSgpCgpmM2MgPC0gYWdlX3NleF9pbXBhY3QzICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9cGN0X2NoYW5nZV9lcHJlZF9hbm51YWwsIHltaW49cGN0X2NoYW5nZV9sb3dlcl9hbm51YWwsIHltYXg9cGN0X2NoYW5nZV91cHBlcl9hbm51YWwsIGdyb3VwPWFjZl9wZXJpb2QsIAogICAgICAgICAgICAgICAgICAgICAgeD1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhY2ZfcGVyaW9kKSwgc2l6ZT0wLjEpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID1wZXJjZW50KSArCiAgZmFjZXRfZ3JpZCgufnNleCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgIiM0RDZDRkEiKSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9Ik1lYW4gYW5udWFsIHJhdGUgb2YgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDk1JSBVSSlcbiBCZWZvcmUgQUNGICgxOTUwLTE5NTYpIHZzLiBhZnRlciBBQ0YgKDE5NTgtMTk2MykiLAogICAgICAgY29sb3VyPSIiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgpmM2MKCmBgYAoKSm9pbiB0b2dldGhlciBmb3IgRmlndXJlIDIuCgpgYGB7cn0KCihmM2EgLyBmM2IgLyBmM2MpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMy5wbmciKSwgaGVpZ2h0PTEyKQoKCmBgYAoKIyMjIyAxMC4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCiAgY291bnRlcmZhY3RfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhMyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkX2NvdW50ZXJmID0gLmVwcmVkKQogIAogICNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlX2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YTMgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4LCBhY2ZfcGVyaW9kKSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCBhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgCiAgCiAgI2ZvciB0aGUgb3ZlcmFsbCBwZXJpb2QKY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGEzICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICBzZWxlY3QoYWdlLCBzZXgsIC5kcmF3LCAuZXByZWQpICAlPiUKICAgICAgZ3JvdXBfYnkoYWdlLCBzZXgsIC5kcmF3KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAlPiUKICAgICAgbXV0YXRlKHllYXIgPSAiT3ZlcmFsbCAoMTk1OC0xOTYzKSIpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGEzICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCwgYWNmX3BlcmlvZCkpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKCmxlZnRfam9pbihjb3VudGVyZmFjdF9hZ2Vfc2V4LCBwb3N0X2NoYW5nZV9hZ2Vfc2V4KSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgZGF0YXRhYmxlKCkKCmNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4LCBwb3N0X2NoYW5nZV9vdmVyYWxsX2FnZV9zZXgpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYpICU+JQogICAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCgpgYGAKCgpgYGB7cn0KCmNvdW50ZXJfcG9zdF9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgdHJhbnNtdXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIHNleCA9IHNleCwKICAgICAgICAgICAgYWdlID0gYWdlLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9ICh7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZTo6Z2x1ZSgie3BjdF9jaGFuZ2V9ICh7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpKQoKCmNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICB0cmFuc211dGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgc2V4ID0gc2V4LAogICAgICAgICAgICBhZ2UgPSBhZ2UsCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH0gKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX0gKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCgoKCgpgYGAKCgoKCiMjIyAxMS4gRGl2aXNpb24tbGV2ZWwgbW9kZWwKCihWZXJ5IG11Y2ggYSB3b3JrIGluIHByb2dyZXNzISkKCmBgYHtyfQoKbWRhdGEzIDwtIGRpdmlzaW9uX2luYyAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKHllYXIgJWluJSBjKDE5NTA6MTk1NikgfiAiYS4gcHJlLWFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1NykgfiAiYi4gYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU4OjE5NjMpIH4gImMuIHBvc3QtYWNmIikpICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKCmdncGxvdChkYXRhID0gdGliYmxlKHggPSBzZXEoZnJvbSA9IDAsIHRvID0gMTUwMCwgYnkgPSAxMCkpLAogICAgICAgYWVzKHggPSB4LCB5ID0gZGdhbW1hKHgsIHNoYXBlID0gMiwgcmF0ZSA9IDAuMDAxKSkpICsKICBnZW9tX2FyZWEoY29sb3IgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgZmlsbCA9ICIjREUwRDkyIikgKwogIHNjYWxlX3hfY29udGludW91cyhOVUxMKSArCiAgc2NhbGVfeV9jb250aW51b3VzKE5VTEwsIGJyZWFrcyA9IE5VTEwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMTUwMCkpICsKICBnZ3RpdGxlKGV4cHJlc3Npb24oYnJtc35+Z2FtbWEoMC41KiIsICIqMC4wMDAxKX5zaGFwZX5wcmlvcikpCgp3aW5mb3JtX3ByaW9yMyA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgICAjcHJpb3IoZ2FtbWEoMiwgMC4wMDAxKSwgY2xhc3MgPSBzaGFwZSksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAwMDEpLCBjbGFzcyA9IGIsIGNvZWYgPSAiYWNmX3BlcmlvZGIuYWNmIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAwMDEpLCBjbGFzcyA9IGIsIGNvZWYgPSAiYWNmX3BlcmlvZGMucG9zdE1hY2YiKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAwMSksIGNsYXNzID0gYiwgY29lZiA9ICJ5X251bSIpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMDAxKSwgY2xhc3MgPSBiLCBjb2VmID0gInlfbnVtOmFjZl9wZXJpb2RiLmFjZiIpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMDAxKSwgY2xhc3MgPSBiLCBjb2VmID0gInlfbnVtOmFjZl9wZXJpb2RjLnBvc3RNYWNmIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz0ic2QiKSkKCgptX3B1bG1vbmFyeV9kaXZpc2lvbl9wcmlvciA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgKDEgKyB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtIHwgZGl2aXNpb24gKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEzLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yMywKICAgICAgICAgICAgICAgICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLAogICAgICAgICAgICAgICAgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKY29uZGl0aW9uYWxfZWZmZWN0cyhtX3B1bG1vbmFyeV9kaXZpc2lvbl9wcmlvcikKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbD1tX3B1bG1vbmFyeV9kaXZpc2lvbl9wcmlvciwgbW9kZWxfZGF0YT1tZGF0YTMsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBvdXRjb21lID0gY2FzZXMsIGdyb3VwaW5nX3ZhciA9IGRpdmlzaW9uLCBkaXZpc2lvbikgKyBzY2FsZV95X2xvZzEwKCkKCgpgYGAKCgoKYGBge3J9CgptX3B1bG1vbmFyeV9kaXZpc2lvbiA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgKDEgfCBkaXZpc2lvbikgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMywKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbigpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yMywKICAgICAgICAgICAgICAgICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIiwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCnN1bW1hcnkobV9wdWxtb25hcnlfZGl2aXNpb24pCnBsb3QobV9wdWxtb25hcnlfZGl2aXNpb24pCnBwX2NoZWNrKG1fcHVsbW9uYXJ5X2RpdmlzaW9uLCB0eXBlPSdlY2RmX292ZXJsYXknKQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbD1tX3B1bG1vbmFyeV9kaXZpc2lvbiwgbW9kZWxfZGF0YT1tZGF0YTMsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBvdXRjb21lID0gY2FzZXMsIGdyb3VwaW5nX3ZhciA9IGRpdmlzaW9uLCBkaXZpc2lvbikKCgpgYGAKCgojIyMgMTIuIENvdW50ZXJmYWN0dWFsIHRhYmxlCgpNYWtlIGEgdGFibGUgb2YgY291bnRlcmZhY3R1YWwgZWZmZWN0cyBmb3IgdGhlIG1hbnVzY3JpcHQKCmBgYHtyfQoKcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFscyA8LSB0aWR5X2NvdW50ZXJmYWN0dWFscyhvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QpCnB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCA8LSB0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKG92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKZXh0cmFwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzKG92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0KQpleHRyYXB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCA8LSB0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKG92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwpCgphZ2Vfc2V4X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwoY291bnRlcl9wb3N0X292ZXJhbGxfYWdlX3NleCkgJT4lIG11dGF0ZShtb2RlbCA9ICJBZ2Utc2V4IikKCmJpbmRfcm93cygKICBiaW5kX3Jvd3MocHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFscywgcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gIlB1bG1vbmFyeSBUQiIsIHNleD1OQSwgYWdlPU5BKSwKICBiaW5kX3Jvd3MoZXh0cmFwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzLCBleHRyYXB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCkgJT4lIG11dGF0ZShtb2RlbCA9ICJFeHRyYS1wdWxtb25hcnkgVEIiLCBzZXg9TkEsIGFnZT1OQSksCiAgYWdlX3NleF9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCkgJT4lCiAgc2VsZWN0KG1vZGVsLCB5ZWFyLCBhZ2UsIHNleCwgZGlmZl9pbmMsIHJyX2luYywgY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkKCgoKYGBgCgoKCgo=